summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author Eric Hameleers <alien@slackware.com>2019-02-05 17:20:06 +0000
committer Eric Hameleers <alien@slackware.com>2019-02-05 17:20:06 +0000
commita31f3babf9cd99c443eb6e5a8228f93a76b87cb1 (patch)
treeb645ed5c8f5f27b9ca317dd671dd08e32fd354e2
parent32c218ce98434be5e28fec6046c37a4bfcaaafdf (diff)
downloadasb-a31f3babf9cd99c443eb6e5a8228f93a76b87cb1.tar.gz
asb-a31f3babf9cd99c443eb6e5a8228f93a76b87cb1.tar.xz
Initial revision
-rw-r--r--wine/build/patches/wine-d3d9-1.7.51.patch4436
-rw-r--r--wine/build/patches/wine-d3d9-1.7.52.patch9951
-rw-r--r--wine/build/patches/wine-d3d9-1.8.patch0
3 files changed, 14387 insertions, 0 deletions
diff --git a/wine/build/patches/wine-d3d9-1.7.51.patch b/wine/build/patches/wine-d3d9-1.7.51.patch
new file mode 100644
index 00000000..dd4b9ea6
--- /dev/null
+++ b/wine/build/patches/wine-d3d9-1.7.51.patch
@@ -0,0 +1,4436 @@
+diff --git a/configure.ac b/configure.ac
+index aec53f6..c30342f 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -65,6 +65,8 @@ AC_ARG_WITH(openal, AS_HELP_STRING([--without-openal],[do not use OpenAL]),
+ AC_ARG_WITH(opencl, AS_HELP_STRING([--without-opencl],[do not use OpenCL]),
+ [if test "x$withval" = "xno"; then ac_cv_header_CL_cl_h=no; ac_cv_header_OpenCL_opencl_h=no; fi])
+ AC_ARG_WITH(opengl, AS_HELP_STRING([--without-opengl],[do not use OpenGL]))
++AC_ARG_WITH(d3dadapter,AS_HELP_STRING([--without-d3dadapter],[do not use native Direct3D]))
++AC_ARG_WITH(d3dadapter-dri2-fallback, AS_HELP_STRING([--without-d3dadapter-dri2-fallback],[add a DRI2 fallback to d3dadapter DRI3 code]))
+ AC_ARG_WITH(osmesa, AS_HELP_STRING([--without-osmesa],[do not use the OSMesa library]))
+ AC_ARG_WITH(oss, AS_HELP_STRING([--without-oss],[do not use the OSS sound support]))
+ AC_ARG_WITH(pcap, AS_HELP_STRING([--without-pcap],[do not use the Packet Capture library]),
+@@ -79,6 +81,8 @@ AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xco
+ [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi])
+ AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]),
+ [if test "x$withval" = "xno"; then ac_cv_header_X11_Xcursor_Xcursor_h=no; fi])
++AC_ARG_WITH(xfixes, AS_HELP_STRING([--without-xfixes],[do not use the Xfixes extension]),
++ [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xfixes_h=no; fi])
+ AC_ARG_WITH(xinerama, AS_HELP_STRING([--without-xinerama],[do not use Xinerama (multi-monitor support)]),
+ [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xinerama_h=no; fi])
+ AC_ARG_WITH(xinput, AS_HELP_STRING([--without-xinput],[do not use the Xinput extension]),
+@@ -378,6 +382,8 @@ AC_CHECK_LIB(ossaudio,_oss_ioctl)
+
+ AC_SUBST(OPENGL_LIBS,"")
+
++AC_SUBST(D3DADAPTER9_LIBS,"")
++
+ dnl **** Check for header files ****
+
+ AC_SYS_LARGEFILE()
+@@ -1107,6 +1113,7 @@ then
+ X11/extensions/XInput2.h \
+ X11/extensions/XShm.h \
+ X11/extensions/Xcomposite.h \
++ X11/extensions/Xfixes.h \
+ X11/extensions/Xinerama.h \
+ X11/extensions/Xrandr.h \
+ X11/extensions/Xrender.h \
+@@ -1222,6 +1229,14 @@ then
+ WINE_NOTICE_WITH(xcomposite,[test "x$ac_cv_lib_soname_Xcomposite" = "x"],
+ [libxcomposite ${notice_platform}development files not found, Xcomposite won't be supported.])
+
++ dnl *** Check for X Fixes extension
++ if test "$ac_cv_header_X11_extensions_Xfixes_h" = "yes"
++ then
++ WINE_CHECK_SONAME(Xfixes,XFixesCreateRegion,,,[$X_LIBS $XLIB $X_EXTRA_LIBS])
++ fi
++ WINE_NOTICE_WITH(xfixes,[test "x$ac_cv_lib_soname_Xfixes" = "x"],
++ [libxfixes ${notice_platform}development files not found, Xfixes won't be supported.])
++
+ dnl *** Check for XICCallback struct
+ AC_CHECK_MEMBERS([XICCallback.callback, XEvent.xcookie],,,
+ [#ifdef HAVE_X11_XLIB_H
+@@ -1264,6 +1279,28 @@ This probably prevents linking to OpenGL. Try deleting the file and restarting c
+ WINE_WARNING_WITH(opengl,[test -n "$opengl_msg"],[$opengl_msg
+ OpenGL and Direct3D won't be supported.])
+
++
++
++ dnl Check for d3dadapter
++ if test "x$with_d3dadapter" != "xno"
++ then
++ D3D_CFLAGS=`pkg-config --cflags d3d`
++ D3D_LIBS=`pkg-config --libs d3d`
++ AC_SUBST(D3D_CFLAGS)
++ AC_SUBST(D3D_LIBS)
++ AC_DEFINE(SONAME_D3DADAPTER9, ["d3dadapter9.so.1"], ["temporary hack"])
++ AC_DEFINE_UNQUOTED(D3D_MODULE_DIR, ["`pkg-config --variable=moduledir d3d`"], ["module dir"])
++ D3DADAPTER9_LIBS="-lxcb -lxcb-dri3 -lxcb-present -lX11-xcb -lxcb-xfixes -lpthread"
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb -lxcb-dri3 -lxcb-present -lX11-xcb -lxcb-xfixes -lpthread"],[D3Dadapter9 requirements not met])
++ if test "x$with_d3dadapter_dri2_fallback" != "xno"
++ then
++ AC_DEFINE(D3DADAPTER9_DRI2, 1, [Whether d3dadapter9 DRI2 fallback is compiled])
++ WINE_CHECK_SONAME(GL,glGenFramebuffers, [D3DADAPTER9_LIBS="-lGL $D3DADAPTER9_LIBS"])
++ WINE_CHECK_SONAME(EGL,eglCreateContext, [D3DADAPTER9_LIBS="-lEGL $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lEGL -lGL -lxcb -lxcb-dri3 -lxcb-present -lX11-xcb -lxcb-xfixes -lpthread"],[D3Dadapter9 DRI2 fallback requirements not met])
++ fi
++ fi
++
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ else
+ X_CFLAGS=""
+diff --git a/dlls/d3d9/Makefile.in b/dlls/d3d9/Makefile.in
+index 1c05f5a..92b458d 100644
+--- a/dlls/d3d9/Makefile.in
++++ b/dlls/d3d9/Makefile.in
+@@ -1,10 +1,11 @@
+ MODULE = d3d9.dll
+ IMPORTLIB = d3d9
+-IMPORTS = dxguid uuid wined3d
++IMPORTS = dxguid uuid advapi32 gdi32 user32 wined3d
+
+ C_SRCS = \
+ buffer.c \
+ d3d9_main.c \
++ d3dadapter9.c \
+ device.c \
+ directx.c \
+ query.c \
+diff --git a/dlls/d3d9/d3d9_main.c b/dlls/d3d9/d3d9_main.c
+index 0afdc04..eb5665d 100644
+--- a/dlls/d3d9/d3d9_main.c
++++ b/dlls/d3d9/d3d9_main.c
+@@ -33,12 +33,63 @@ void WINAPI DebugSetMute(void) {
+ /* nothing to do */
+ }
+
++static BOOL try_native(void)
++{
++ HKEY defkey = 0, appkey = 0;
++ DWORD type, data = 0;
++ DWORD size = sizeof(DWORD);
++ DWORD len;
++ char buffer[MAX_PATH];
++
++ /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */
++ if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &defkey ) ) defkey = 0;
++
++ len = GetModuleFileNameA( 0, buffer, MAX_PATH );
++ if (len && len < MAX_PATH)
++ {
++ HKEY tmpkey;
++ /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */
++ if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
++ {
++ char *p, *appname = buffer;
++ if ((p = strrchr( appname, '/' ))) appname = p + 1;
++ if ((p = strrchr( appname, '\\' ))) appname = p + 1;
++ strcat( appname, "\\Direct3D" );
++ TRACE("appname = [%s]\n", appname);
++ if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
++ RegCloseKey( tmpkey );
++ }
++ }
++
++ if (!(appkey && !RegQueryValueExA(appkey, "UseNative", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD))) {
++ if (!(defkey && !RegQueryValueExA(defkey, "UseNative", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD))) {
++ data = 0;
++ }
++ }
++
++ if (appkey) RegCloseKey( appkey );
++ if (defkey) RegCloseKey( defkey );
++
++ if (!data)
++ FIXME("\033[1;33m\nNative Direct3D 9 is disabled."
++ "\nFor more information visit https://wiki.ixit.cz/d3d9\n\033[0m");
++
++ return data ? TRUE : FALSE;
++}
++
+ IDirect3D9 * WINAPI DECLSPEC_HOTPATCH Direct3DCreate9(UINT sdk_version)
+ {
+ struct d3d9 *object;
+
+ TRACE("sdk_version %#x.\n", sdk_version);
+
++ if (try_native()) {
++ IDirect3D9 *native;
++ if (SUCCEEDED(d3dadapter9_new(FALSE, (IDirect3D9Ex **)&native))) {
++ return native;
++ }
++ }
++
+ if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+ return NULL;
+
+@@ -60,6 +111,10 @@ HRESULT WINAPI DECLSPEC_HOTPATCH Direct3DCreate9Ex(UINT sdk_version, IDirect3D9E
+
+ TRACE("sdk_version %#x, d3d9ex %p.\n", sdk_version, d3d9ex);
+
++ if (try_native()) {
++ if (SUCCEEDED(d3dadapter9_new(TRUE, d3d9ex))) { return D3D_OK; }
++ }
++
+ if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+@@ -90,6 +145,25 @@ void* WINAPI Direct3DShaderValidatorCreate9(void)
+ return NULL;
+ }
+
++/*******************************************************************
++ * DllMain
++ */
++BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved)
++{
++ switch (reason)
++ {
++ case DLL_PROCESS_ATTACH:
++ d3dadapter9_init(inst);
++ break;
++
++ case DLL_PROCESS_DETACH:
++ d3dadapter9_destroy(inst);
++ break;
++ }
++
++ return TRUE;
++}
++
+ /***********************************************************************
+ * D3DPERF_BeginEvent (D3D9.@)
+ */
+diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h
+index d12805f..cdc1f07 100644
+--- a/dlls/d3d9/d3d9_private.h
++++ b/dlls/d3d9/d3d9_private.h
+@@ -39,6 +39,9 @@
+ #include "d3d9.h"
+ #include "wine/wined3d.h"
+
++extern void d3dadapter9_init(HINSTANCE hinst);
++extern void d3dadapter9_destroy(HINSTANCE hinst);
++
+ extern HRESULT vdecl_convert_fvf(DWORD FVF, D3DVERTEXELEMENT9 **ppVertexElements) DECLSPEC_HIDDEN;
+ D3DFORMAT d3dformat_from_wined3dformat(enum wined3d_format_id format) DECLSPEC_HIDDEN;
+ enum wined3d_format_id wined3dformat_from_d3dformat(D3DFORMAT format) DECLSPEC_HIDDEN;
+@@ -132,6 +135,7 @@ struct d3d9
+
+ BOOL d3d9_init(struct d3d9 *d3d9, BOOL extended) DECLSPEC_HIDDEN;
+ void filter_caps(D3DCAPS9* pCaps) DECLSPEC_HIDDEN;
++HRESULT d3dadapter9_new(boolean ex, IDirect3D9Ex **ppOut);
+
+ struct fvf_declaration
+ {
+diff --git a/dlls/d3d9/d3dadapter9.c b/dlls/d3d9/d3dadapter9.c
+new file mode 100644
+index 0000000..3c75ae0
+--- /dev/null
++++ b/dlls/d3d9/d3dadapter9.c
+@@ -0,0 +1,943 @@
++/*
++ * X11DRV IDirect3D9 interface using ID3DAdapter9
++ *
++ * Copyright 2013 Joakim Sindholt
++ * Christoph Bumiller
++ *
++ * 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"
++
++#include <d3d9.h>
++
++#ifdef SONAME_D3DADAPTER9
++
++#include "wine/d3dadapter.h"
++#include "wine/gdi_driver.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
++
++/* 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;
++
++ struct d3dadapter_funcs *funcs;
++ /* fake window for getting driver funcs */
++ HWND hwnd;
++ HDC hdc;
++
++ /* true if it implements IDirect3D9Ex */
++ boolean ex;
++};
++
++/* 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);
++ }
++
++ if (This->hdc) { ReleaseDC(This->hwnd, This->hdc); }
++ if (This->hwnd) { DestroyWindow(This->hwnd); }
++
++ 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;
++
++ 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;
++ }
++ hr = This->funcs->create_present_group(group->devname, ordinal,
++ hFocusWindow,
++ pPresentationParameters,
++ nparams, &present);
++ }
++
++ 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 = This->funcs->create_adapter9(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
++};
++
++#define D3D9_FAKE_WNDCLASS "FAKED3D9WINDOW"
++
++void
++d3dadapter9_init( HINSTANCE hinst )
++{
++ WNDCLASSA wc;
++
++ wc.style = CS_HREDRAW | CS_VREDRAW;
++ wc.lpfnWndProc = DefWindowProcA;
++ wc.cbClsExtra = 0;
++ wc.cbWndExtra = 0;
++ wc.hInstance = hinst;
++ wc.hIcon = LoadIconA(NULL, (LPCSTR)IDI_WINLOGO);
++ wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
++ wc.hbrBackground = NULL;
++ wc.lpszMenuName = NULL;
++ wc.lpszClassName = D3D9_FAKE_WNDCLASS;
++
++ if (!RegisterClassA(&wc)) {
++ ERR("Unable to register window to retrieve driver info.\n");
++ }
++}
++
++void
++d3dadapter9_destroy( HINSTANCE hinst )
++{
++ UnregisterClassA(D3D9_FAKE_WNDCLASS, hinst);
++}
++
++static int
++load_adapter_funcs( struct d3dadapter9 *This )
++{
++ This->hwnd = CreateWindowA(D3D9_FAKE_WNDCLASS, "D3DAdapter9 fake window",
++ WS_OVERLAPPEDWINDOW, 10, 10, 10, 10,
++ NULL, NULL, NULL, NULL);
++ if (!This->hwnd) {
++ ERR("Unable to create fake window to retrieve driver info.\n");
++ return FALSE;
++ }
++ This->hdc = GetDC(This->hwnd);
++ if (!This->hdc) {
++ ERR("Unable to get fake window DC to retrieve driver info.\n");
++ return FALSE;
++ }
++
++ This->funcs =
++ __wine_get_d3dadapter_driver(This->hdc, WINE_D3DADAPTER_DRIVER_VERSION);
++ if (!This->funcs || !This->funcs->create_adapter9) {
++ WARN("Your display driver doesn't support native D3D9 adapters.\n");
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++HRESULT
++d3dadapter9_new( 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;
++
++ if (!load_adapter_funcs(This)) {
++ 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;
++}
++
++#else
++
++HRESULT
++d3dadapter9_new( boolean ex,
++ IDirect3D9Ex **ppOut )
++{
++ return D3DERR_NOTAVAILABLE;
++}
++
++void
++d3dadapter9_init( HINSTANCE hinst )
++{
++}
++
++void
++d3dadapter9_destroy( HINSTANCE hinst )
++{
++}
++
++#endif /* SONAME_D3DADAPTER9 */
+diff --git a/dlls/gdi32/Makefile.in b/dlls/gdi32/Makefile.in
+index 6cc026c..703968d 100644
+--- a/dlls/gdi32/Makefile.in
++++ b/dlls/gdi32/Makefile.in
+@@ -12,6 +12,7 @@ C_SRCS = \
+ bitmap.c \
+ brush.c \
+ clipping.c \
++ d3dadapter.c \
+ dc.c \
+ dib.c \
+ dibdrv/bitblt.c \
+diff --git a/dlls/gdi32/d3dadapter.c b/dlls/gdi32/d3dadapter.c
+new file mode 100644
+index 0000000..fbf2cd0
+--- /dev/null
++++ b/dlls/gdi32/d3dadapter.c
+@@ -0,0 +1,41 @@
++/*
++ * d3dadapter function forwarding to the display driver
++ *
++ * Copyright (c) 1999 Lionel Ulmer
++ * Copyright (c) 2005 Raphael Junqueira
++ * Copyright (c) 2006 Roderick Colenbrander
++ * Copyright (c) 2013 Joakim Sindholt
++ *
++ * 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 "gdi_private.h"
++
++/***********************************************************************
++ * __wine_get_d3dadapter_driver (GDI32.@)
++ */
++struct d3dadapter_funcs * CDECL __wine_get_d3dadapter_driver( HDC hdc, UINT version )
++{
++ struct d3dadapter_funcs *ret = NULL;
++ DC * dc = get_dc_ptr( hdc );
++
++ if (dc)
++ {
++ PHYSDEV physdev = GET_DC_PHYSDEV( dc, wine_get_d3dadapter_driver );
++ ret = physdev->funcs->wine_get_d3dadapter_driver( physdev, version );
++ release_dc_ptr( dc );
++ }
++ return ret;
++}
+diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c
+index 7203a8d..70bbb23 100644
+--- a/dlls/gdi32/dibdrv/dc.c
++++ b/dlls/gdi32/dibdrv/dc.c
+@@ -523,6 +523,7 @@ const struct gdi_dc_funcs dib_driver =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ dibdrv_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_DIB_DRV /* priority */
+ };
+
+@@ -1143,5 +1144,6 @@ static const struct gdi_dc_funcs window_driver =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ windrv_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_DIB_DRV + 10 /* priority */
+ };
+diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
+index a6b138c..3c88600 100644
+--- a/dlls/gdi32/driver.c
++++ b/dlls/gdi32/driver.c
+@@ -633,6 +633,11 @@ static struct opengl_funcs *nulldrv_wine_get_wgl_driver( PHYSDEV dev, UINT versi
+ return (void *)-1;
+ }
+
++static struct d3dadapter_funcs *nulldrv_wine_get_d3dadapter_driver( PHYSDEV dev, UINT version )
++{
++ return NULL;
++}
++
+ const struct gdi_dc_funcs null_driver =
+ {
+ nulldrv_AbortDoc, /* pAbortDoc */
+@@ -762,6 +767,7 @@ const struct gdi_dc_funcs null_driver =
+ nulldrv_UnrealizePalette, /* pUnrealizePalette */
+ nulldrv_WidenPath, /* pWidenPath */
+ nulldrv_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ nulldrv_wine_get_d3dadapter_driver, /* wine_get_d3dadapter_driver */
+
+ GDI_PRIORITY_NULL_DRV /* priority */
+ };
+diff --git a/dlls/gdi32/enhmfdrv/init.c b/dlls/gdi32/enhmfdrv/init.c
+index 34b3de6..90982b3 100644
+--- a/dlls/gdi32/enhmfdrv/init.c
++++ b/dlls/gdi32/enhmfdrv/init.c
+@@ -163,6 +163,7 @@ static const struct gdi_dc_funcs EMFDRV_Funcs =
+ NULL, /* pUnrealizePalette */
+ EMFDRV_WidenPath, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
+index 60ffc45..95d8fce 100644
+--- a/dlls/gdi32/freetype.c
++++ b/dlls/gdi32/freetype.c
+@@ -8545,6 +8545,7 @@ static const struct gdi_dc_funcs freetype_funcs =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_FONT_DRV /* priority */
+ };
+
+diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec
+index 8bba686..c248d5b 100644
+--- a/dlls/gdi32/gdi32.spec
++++ b/dlls/gdi32/gdi32.spec
+@@ -521,3 +521,6 @@
+
+ # OpenGL
+ @ cdecl __wine_get_wgl_driver(long long)
++
++# Native Direct3D
++@ cdecl __wine_get_d3dadapter_driver(long long)
+diff --git a/dlls/gdi32/mfdrv/init.c b/dlls/gdi32/mfdrv/init.c
+index 50f8ba3..e35d7d8 100644
+--- a/dlls/gdi32/mfdrv/init.c
++++ b/dlls/gdi32/mfdrv/init.c
+@@ -226,6 +226,7 @@ static const struct gdi_dc_funcs MFDRV_Funcs =
+ NULL, /* pUnrealizePalette */
+ MFDRV_WidenPath, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/gdi32/path.c b/dlls/gdi32/path.c
+index e09cd0b..6dc322c 100644
+--- a/dlls/gdi32/path.c
++++ b/dlls/gdi32/path.c
+@@ -2345,5 +2345,6 @@ const struct gdi_dc_funcs path_driver =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_PATH_DRV /* priority */
+ };
+diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c
+index 9f18ac4..669a7ba 100644
+--- a/dlls/winemac.drv/gdi.c
++++ b/dlls/winemac.drv/gdi.c
+@@ -538,6 +538,7 @@ static const struct gdi_dc_funcs macdrv_funcs =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ macdrv_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/wineps.drv/init.c b/dlls/wineps.drv/init.c
+index 2cdb071..6e2cf0f 100644
+--- a/dlls/wineps.drv/init.c
++++ b/dlls/wineps.drv/init.c
+@@ -950,6 +950,7 @@ static const struct gdi_dc_funcs psdrv_funcs =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in
+index 463eefd..65d32ed 100644
+--- a/dlls/winex11.drv/Makefile.in
++++ b/dlls/winex11.drv/Makefile.in
+@@ -2,13 +2,15 @@ MODULE = winex11.drv
+ IMPORTS = uuid user32 gdi32 advapi32
+ DELAYIMPORTS = comctl32 ole32 shell32 imm32
+ EXTRAINCL = $(X_CFLAGS)
+-EXTRALIBS = $(X_LIBS) $(X_EXTRA_LIBS)
++EXTRALIBS = $(X_LIBS) $(X_EXTRA_LIBS) $(D3DADAPTER9_LIBS)
+
+ C_SRCS = \
+ bitblt.c \
+ brush.c \
+ clipboard.c \
++ d3dadapter.c \
+ desktop.c \
++ dri3.c \
+ event.c \
+ graphics.c \
+ ime.c \
+diff --git a/dlls/winex11.drv/d3dadapter.c b/dlls/winex11.drv/d3dadapter.c
+new file mode 100644
+index 0000000..2296155
+--- /dev/null
++++ b/dlls/winex11.drv/d3dadapter.c
+@@ -0,0 +1,1189 @@
++/*
++ * X11DRV ID3DAdapter9 support functions
++ *
++ * Copyright 2013 Joakim Sindholt
++ * Christoph Bumiller
++ *
++ * 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);
++
++#if defined(SONAME_LIBXEXT) && \
++ defined(SONAME_LIBXFIXES) && \
++ defined(SONAME_D3DADAPTER9)
++
++#include "wine/d3dadapter.h"
++#include "wine/library.h"
++#include "wine/unicode.h"
++
++#include "x11drv.h"
++
++#include <d3dadapter/drm.h>
++
++#include "xfixes.h"
++#include "dri3.h"
++
++#include <libdrm/drm.h>
++#include <sys/ioctl.h>
++#include <errno.h>
++#include <fcntl.h>
++
++#ifndef D3DPRESENT_DONOTWAIT
++#define D3DPRESENT_DONOTWAIT 0x00000001
++#endif
++
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR 1
++#ifdef ID3DPresent_GetWindowOccluded
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 1
++#else
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 0
++#endif
++
++static const struct D3DAdapter9DRM *d3d9_drm = NULL;
++#ifdef D3DADAPTER9_DRI2
++static int is_dri2_fallback = 0;
++#endif
++
++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 );
++#endif
++
++static struct d3d_wnd_hooks d3d_hooks;
++
++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 occluded;
++};
++
++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(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(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
++ ChangeDisplaySettingsExW(This->devname, &(This->initial_mode), 0, CDS_FULLSCREEN, NULL);
++ PRESENTDestroy(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,
++ BOOL first_time);
++
++static HRESULT WINAPI
++DRI3Present_SetPresentParameters( struct DRI3Present *This,
++ D3DPRESENT_PARAMETERS *pPresentationParameters,
++ D3DDISPLAYMODEEX *pFullscreenDisplayMode )
++{
++ if (pFullscreenDisplayMode)
++ FIXME("Ignoring pFullscreenDisplayMode\n");
++#ifdef ID3DPresent_GetWindowOccluded
++ dri3_present_register_window_hook(This);
++#endif
++ return DRI3Present_ChangePresentParameters(This, pPresentationParameters, FALSE);
++}
++
++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(gdi_display, DefaultScreen(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(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(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(hWndOverride);
++ } else if (This->params.hDeviceWindow) {
++ d3d = get_d3d_drawable(This->params.hDeviceWindow);
++ } else {
++ d3d = get_d3d_drawable(This->focus_wnd);
++ }
++ if (!d3d) { return D3DERR_DRIVERINTERNALERROR; }
++
++ 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(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;
++}
++
++#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;
++ 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;
++ switch (wndprocparams.message) {
++ case WM_ACTIVATE:
++ if(wndprocparams.wParam == WA_INACTIVE) {
++ if (hook->present && !hook->present->params.Windowed) {
++ ShowWindow(hook->present->params.hDeviceWindow, SW_MINIMIZE);
++ ChangeDisplaySettingsExW(hook->present->devname, &(hook->present->initial_mode), 0, 0, NULL);
++ hook->present->occluded = TRUE;
++ }
++ } else {
++ if (hook->present && !hook->present->params.Windowed && hook->present->occluded) {
++ ShowWindow(hook->present->params.hDeviceWindow, SW_RESTORE);
++ hook->present->occluded = FALSE;
++ }
++ }
++ 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 D3D_OK;
++ }
++ /* 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 )
++{
++ 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,
++ BOOL first_time)
++{
++ HWND draw_window;
++ RECT rect;
++ LONG hr;
++
++ (void) first_time; /* will be used to manage screen res if windowed mode change */
++ /* TODO: don't do anything if nothing changed */
++ /* sanitize presentation parameters */
++ draw_window = params->hDeviceWindow ? params->hDeviceWindow : This->focus_wnd;
++
++ 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 (!params->Windowed) {
++ /* TODO Store initial config and restore it when leaving fullscreen, or when leaving wine*/
++ LONG style, exstyle;
++ DEVMODEW newMode;
++
++ ZeroMemory(&newMode, sizeof(DEVMODEW));
++ newMode.dmPelsWidth = params->BackBufferWidth;
++ newMode.dmPelsHeight = params->BackBufferHeight;
++ newMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
++ newMode.dmSize = sizeof(DEVMODEW);
++ hr = ChangeDisplaySettingsExW(This->devname, &newMode, 0, CDS_FULLSCREEN, NULL);
++ if (hr != DISP_CHANGE_SUCCESSFUL) {
++ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++ return D3DERR_INVALIDCALL;
++ }
++ style = fullscreen_style(0);
++ exstyle = fullscreen_exstyle(0);
++
++ SetWindowLongW(draw_window, GWL_STYLE, style);
++ SetWindowLongW(draw_window, GWL_EXSTYLE, exstyle);
++ hr = SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth, params->BackBufferHeight,
++ SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
++ if (!hr) {
++ ERR("SetWindowLongW failed with 0x%08X\n", GetLastError());
++ return D3DERR_INVALIDCALL;
++ }
++ } else if (!first_time && !This->params.Windowed) {
++ hr = ChangeDisplaySettingsExW(This->devname, &(This->initial_mode), 0, CDS_FULLSCREEN, NULL);
++ if (hr != DISP_CHANGE_SUCCESSFUL) {
++ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++ return D3DERR_INVALIDCALL;
++ }
++ }
++ SetForegroundWindow(draw_window);
++
++ This->params = *params;
++ return D3D_OK;
++}
++
++static HRESULT
++DRI3Present_new( Display *dpy,
++ const WCHAR *devname,
++ D3DPRESENT_PARAMETERS *params,
++ HWND focus_wnd,
++ struct DRI3Present **out )
++{
++ struct DRI3Present *This;
++ HRESULT hr;
++
++ 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->vtable = &DRI3Present_vtable;
++ This->refs = 1;
++ This->focus_wnd = focus_wnd;
++
++ 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);
++
++ hr = DRI3Present_ChangePresentParameters(This, params, TRUE);
++ if (hr != D3D_OK)
++ return hr;
++
++ PRESENTInit(dpy, &(This->present_priv));
++#ifdef D3DADAPTER9_DRI2
++ if (is_dri2_fallback)
++ DRI2FallbackInit(dpy, &(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;
++};
++
++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) {
++ 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(gdi_display, This->present_backends[0]->devname,
++ pPresentationParameters, 0, (struct DRI3Present **)ppPresent);
++ 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
++};
++
++static HRESULT
++dri3_create_present_group( const WCHAR *device_name,
++ UINT adapter,
++ HWND focus_wnd,
++ D3DPRESENT_PARAMETERS *params,
++ unsigned nparams,
++ ID3DPresentGroup **group )
++{
++ 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->vtable = &DRI3PresentGroup_vtable;
++ This->refs = 1;
++ 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) {
++ /* 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]);
++ if (FAILED(hr)) {
++ DRI3PresentGroup_Release(This);
++ return hr;
++ }
++ }
++
++ *group = (ID3DPresentGroup *)This;
++ TRACE("Returning %p\n", *group);
++
++ return D3D_OK;
++}
++
++static HRESULT
++dri3_create_adapter9( 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;
++}
++
++static BOOL
++has_d3dadapter( void )
++{
++ static const void * WINAPI (*pD3DAdapter9GetProc)(const char *);
++ static void *handle = NULL;
++ static int done = 0;
++
++ int xfmaj, xfmin;
++ char errbuf[256];
++
++ /* like in opengl.c (single threaded assumption OK?) */
++ if (done) { return handle != NULL; }
++ done = 1;
++
++ /* */
++ if (!usexfixes) {
++ ERR("%s needs Xfixes.\n", SONAME_D3DADAPTER9);
++ return FALSE;
++ }
++
++ 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
++ }
++
++ /* query XFixes */
++ if (!pXFixesQueryVersion(gdi_display, &xfmaj, &xfmin)) {
++ ERR("Unable to query XFixes extension.\n");
++ return D3DERR_DRIVERINTERNALERROR;
++ }
++ TRACE("Got XFixes version %u.%u\n", xfmaj, xfmin);
++ 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;
++}
++
++static struct d3dadapter_funcs dri3_driver = {
++ dri3_create_present_group, /* create_present_group */
++ dri3_create_adapter9, /* create_adapter9 */
++};
++
++struct d3dadapter_funcs *
++get_d3d_dri3_driver(UINT version)
++{
++ if (version != WINE_D3DADAPTER_DRIVER_VERSION) {
++ ERR("Version mismatch. d3d* wants %u but winex11 has "
++ "version %u\n", version, WINE_D3DADAPTER_DRIVER_VERSION);
++ return NULL;
++ }
++ if (has_d3dadapter()) { return &dri3_driver; }
++ return NULL;
++}
++
++#else /* defined(SONAME_LIBXEXT) && \
++ defined(SONAME_LIBXFIXES) && \
++ defined(SONAME_D3DADAPTER9) */
++
++struct d3dadapter_funcs;
++
++void
++destroy_d3dadapter_drawable(HWND hwnd)
++{
++}
++
++static BOOL
++has_d3dadapter( void )
++{
++ FIXME("\033[0;31m\nWine source code has been compiled without native Direct3D 9 support."
++ "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
++ return FALSE;
++}
++
++struct d3dadapter_funcs *
++get_d3d_dri3_driver(UINT version)
++{
++ return NULL;
++}
++
++#endif /* defined(SONAME_LIBXEXT) && \
++ defined(SONAME_LIBXFIXES) && \
++ defined(SONAME_D3DADAPTER9) */
+diff --git a/dlls/winex11.drv/dri3.c b/dlls/winex11.drv/dri3.c
+new file mode 100644
+index 0000000..32f4e20
+--- /dev/null
++++ b/dlls/winex11.drv/dri3.c
+@@ -0,0 +1,1339 @@
++/*
++ * 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
++ */
++
++
++#include "config.h"
++#include "wine/debug.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
++
++#if defined(SONAME_LIBXEXT) && defined(SONAME_LIBXFIXES)
++
++#include "x11drv.h"
++#include "wine/d3dadapter.h"
++
++
++#include <stdlib.h>
++#include <fcntl.h>
++
++#include <X11/Xlib.h>
++#include <X11/extensions/Xfixes.h>
++#include <X11/Xlib-xcb.h>
++
++#include "xfixes.h"
++#include "dri3.h"
++#include <pthread.h>
++#include "winbase.h" /* for Sleep */
++
++#ifdef D3DADAPTER9_DRI2
++#include <unistd.h>
++#include <sys/ioctl.h>
++#include <stdio.h>
++#include <string.h>
++#include "x11drv.h"
++#include <X11/Xlibint.h>
++#include <X11/extensions/dri2tokens.h>
++#include <X11/extensions/dri2proto.h>
++#include <X11/extensions/extutil.h>
++#define GL_GLEXT_PROTOTYPES 1
++#define EGL_EGLEXT_PROTOTYPES 1
++#define GL_GLEXT_LEGACY 1
++#include <GL/gl.h>
++/* workaround gl header bug */
++#define glBlendColor glBlendColorLEV
++#define glBlendEquation glBlendEquationLEV
++#include <GL/glext.h>
++#include <EGL/egl.h>
++#include <EGL/eglext.h>
++#include <libdrm/drm_fourcc.h>
++#include <libdrm/drm.h>
++/*GLAPI void GLAPIENTRY glFlush( void );
++
++GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers);
++GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer);
++GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
++GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
++GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
++GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
++GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures);
++EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);*/
++
++typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
++typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
++typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
++
++#endif
++
++BOOL
++DRI3CheckExtension(Display *dpy, int major, int minor)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ xcb_dri3_query_version_cookie_t dri3_cookie;
++ xcb_dri3_query_version_reply_t *dri3_reply;
++ xcb_generic_error_t *error;
++ const xcb_query_extension_reply_t *extension;
++ int fd;
++
++ xcb_prefetch_extension_data(xcb_connection, &xcb_dri3_id);
++
++ extension = xcb_get_extension_data(xcb_connection, &xcb_dri3_id);
++ if (!(extension && extension->present)) {
++ ERR("DRI3 extension is not present\n");
++ return FALSE;
++ }
++
++ dri3_cookie = xcb_dri3_query_version(xcb_connection, major, minor);
++
++ dri3_reply = xcb_dri3_query_version_reply(xcb_connection, dri3_cookie, &error);
++ if (!dri3_reply) {
++ free(error);
++ ERR("Issue getting requested version of DRI3: %d,%d\n", major, minor);
++ return FALSE;
++ }
++
++ if (!DRI3Open(dpy, DefaultScreen(dpy), &fd)) {
++ ERR("DRI3 advertised, but not working\n");
++ return FALSE;
++ }
++ close(fd);
++
++ TRACE("DRI3 version %d,%d found. %d %d requested\n", major, minor, (int)dri3_reply->major_version, (int)dri3_reply->minor_version);
++ free(dri3_reply);
++
++ return TRUE;
++}
++
++#ifdef D3DADAPTER9_DRI2
++
++struct DRI2priv {
++ Display *dpy;
++ EGLDisplay display;
++ EGLContext context;
++ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func;
++ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func;
++ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func;
++};
++
++/* TODO: We don't free memory properly. When exiting, eglTerminate doesn't work well(crash), and things are freed automatically. Rely on it */
++
++BOOL
++DRI2FallbackInit(Display *dpy, struct DRI2priv **priv)
++{
++ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func;
++ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func;
++ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT_func;
++ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func;
++ EGLDisplay display;
++ EGLint major, minor;
++ EGLConfig config;
++ EGLContext context;
++ EGLint i;
++ EGLBoolean b;
++ EGLenum current_api = 0;
++ const char *extensions;
++ EGLint config_attribs[] = {
++ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
++ EGL_NONE
++ };
++ EGLint context_compatibility_attribs[] = {
++ EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR,
++ EGL_NONE
++ };
++
++ current_api = eglQueryAPI();
++ eglGetPlatformDisplayEXT_func = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT");
++ if (!eglGetPlatformDisplayEXT_func)
++ return FALSE;
++ display = eglGetPlatformDisplayEXT_func(EGL_PLATFORM_X11_EXT, dpy, NULL);
++ if (!display)
++ return FALSE;
++ if (eglInitialize(display, &major, &minor) != EGL_TRUE)
++ goto clean_egl_display;
++
++ extensions = eglQueryString(display, EGL_CLIENT_APIS);
++ if (!extensions || !strstr(extensions, "OpenGL"))
++ goto clean_egl_display;
++
++ extensions = eglQueryString(display, EGL_EXTENSIONS);
++ if (!extensions || !strstr(extensions, "EGL_EXT_image_dma_buf_import") ||
++ !strstr(extensions, "EGL_KHR_create_context") ||
++ !strstr(extensions, "EGL_KHR_surfaceless_context") ||
++ !strstr(extensions, "EGL_KHR_image_base"))
++ goto clean_egl_display;
++
++ if (!eglChooseConfig(display, config_attribs, &config, 1, &i))
++ goto clean_egl_display;
++
++ b = eglBindAPI(EGL_OPENGL_API);
++ if (b == EGL_FALSE)
++ goto clean_egl_display;
++ context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_compatibility_attribs);
++ if (context == EGL_NO_CONTEXT)
++ goto clean_egl_display;
++
++ glEGLImageTargetTexture2DOES_func = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES");
++ eglCreateImageKHR_func = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
++ eglDestroyImageKHR_func = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
++ if (!eglCreateImageKHR_func || !glEGLImageTargetTexture2DOES_func || !eglDestroyImageKHR_func) {
++ ERR("eglGetProcAddress failed !");
++ goto clean_egl_display;
++ }
++
++ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++
++ *priv = calloc(1, sizeof(struct DRI2priv));
++ if (!*priv)
++ goto clean_egl;
++ (*priv)->dpy = dpy;
++ (*priv)->display = display;
++ (*priv)->context = context;
++ (*priv)->glEGLImageTargetTexture2DOES_func = glEGLImageTargetTexture2DOES_func;
++ (*priv)->eglCreateImageKHR_func = eglCreateImageKHR_func;
++ (*priv)->eglDestroyImageKHR_func = eglDestroyImageKHR_func;
++ eglBindAPI(current_api);
++ return TRUE;
++
++clean_egl:
++clean_egl_display:
++ eglTerminate(display);
++ eglBindAPI(current_api);
++ return FALSE;
++}
++
++/* hypothesis: at this step all textures, etc are destroyed */
++void
++DRI2FallbackDestroy(struct DRI2priv *priv)
++{
++ EGLenum current_api;
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++ eglMakeCurrent(priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglDestroyContext(priv->display, priv->context);
++ eglTerminate(priv->display);
++ eglBindAPI(current_api);
++ free(priv);
++}
++
++BOOL
++DRI2FallbackCheckSupport(Display *dpy)
++{
++ struct DRI2priv *priv;
++ int fd;
++ if (!DRI2FallbackInit(dpy, &priv))
++ return FALSE;
++ DRI2FallbackDestroy(priv);
++ if (!DRI2FallbackOpen(dpy, DefaultScreen(dpy), &fd))
++ return FALSE;
++ close(fd);
++ return TRUE;
++}
++
++#endif
++
++BOOL
++PRESENTCheckExtension(Display *dpy, int major, int minor)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ xcb_present_query_version_cookie_t present_cookie;
++ xcb_present_query_version_reply_t *present_reply;
++ xcb_generic_error_t *error;
++ const xcb_query_extension_reply_t *extension;
++
++ xcb_prefetch_extension_data(xcb_connection, &xcb_present_id);
++
++ extension = xcb_get_extension_data(xcb_connection, &xcb_present_id);
++ if (!(extension && extension->present)) {
++ ERR("PRESENT extension is not present\n");
++ return FALSE;
++ }
++
++ present_cookie = xcb_present_query_version(xcb_connection, major, minor);
++
++ present_reply = xcb_present_query_version_reply(xcb_connection, present_cookie, &error);
++ if (!present_reply) {
++ free(error);
++ ERR("Issue getting requested version of PRESENT: %d,%d\n", major, minor);
++ return FALSE;
++ }
++
++ TRACE("PRESENT version %d,%d found. %d %d requested\n", major, minor, (int)present_reply->major_version, (int)present_reply->minor_version);
++ free(present_reply);
++
++ return TRUE;
++}
++
++BOOL
++DRI3Open(Display *dpy, int screen, int *device_fd)
++{
++ xcb_dri3_open_cookie_t cookie;
++ xcb_dri3_open_reply_t *reply;
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ int fd;
++ Window root = RootWindow(dpy, screen);
++
++ cookie = xcb_dri3_open(xcb_connection, root, 0);
++
++ reply = xcb_dri3_open_reply(xcb_connection, cookie, NULL);
++ if (!reply)
++ return FALSE;
++
++ if (reply->nfd != 1) {
++ free(reply);
++ return FALSE;
++ }
++
++ fd = xcb_dri3_open_reply_fds(xcb_connection, reply)[0];
++ fcntl(fd, F_SETFD, FD_CLOEXEC);
++
++ *device_fd = fd;
++ free(reply);
++
++ return TRUE;
++}
++
++#ifdef D3DADAPTER9_DRI2
++
++static XExtensionInfo _dri2_info_data;
++static XExtensionInfo *dri2_info = &_dri2_info_data;
++static char dri2_name[] = DRI2_NAME;
++
++#define DRI2CheckExtension(dpy, i, val) \
++ XextCheckExtension(dpy, i, dri2_name, val)
++
++
++static int
++close_display(Display *dpy,
++ XExtCodes *codes);
++static Bool
++wire_to_event(Display *dpy,
++ XEvent *re,
++ xEvent *event);
++static Status
++event_to_wire(Display *dpy,
++ XEvent *re,
++ xEvent *event);
++static int
++error( Display *dpy,
++ xError *err,
++ XExtCodes *codes,
++ int *ret_code );
++static XExtensionHooks dri2_hooks = {
++ NULL, /* create_gc */
++ NULL, /* copy_gc */
++ NULL, /* flush_gc */
++ NULL, /* free_gc */
++ NULL, /* create_font */
++ NULL, /* free_font */
++ close_display, /* close_display */
++ wire_to_event, /* wire_to_event */
++ event_to_wire, /* event_to_wire */
++ error, /* error */
++ NULL, /* error_string */
++};
++static XEXT_GENERATE_CLOSE_DISPLAY(close_display, dri2_info);
++static XEXT_GENERATE_FIND_DISPLAY(find_display, dri2_info,
++ dri2_name, &dri2_hooks, 0, NULL);
++static Bool
++wire_to_event(Display *dpy,
++ XEvent *re,
++ xEvent *event)
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ DRI2CheckExtension(dpy, info, False);
++ TRACE("dri2 wire_to_event\n");
++ return False;
++}
++static Status
++event_to_wire(Display *dpy,
++ XEvent *re,
++ xEvent *event)
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ DRI2CheckExtension(dpy, info, False);
++ TRACE("dri2 event_to_wire\n");
++ return False;
++}
++static int
++error(Display *dpy,
++ xError *err,
++ XExtCodes *codes,
++ int *ret_code)
++{
++ TRACE("dri2 error\n");
++ return False;
++}
++
++#define XALIGN(x) (((x) + 3) & (~3))
++
++static BOOL
++DRI2Connect(Display *dpy,
++ XID window,
++ unsigned driver_type,
++ char **device )
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ xDRI2ConnectReply rep;
++ xDRI2ConnectReq *req;
++ int dev_len, driv_len;
++ char *driver;
++
++ DRI2CheckExtension(dpy, info, False);
++
++ LockDisplay(dpy);
++ GetReq(DRI2Connect, req);
++ req->reqType = info->codes->major_opcode;
++ req->dri2ReqType = X_DRI2Connect;
++ req->window = window;
++ req->driverType = driver_type;
++ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++
++ /* check string lengths */
++ dev_len = rep.deviceNameLength;
++ driv_len = rep.driverNameLength;
++ if (dev_len == 0 || driv_len == 0) {
++ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len));
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++
++ /* read out driver */
++ driver = HeapAlloc(GetProcessHeap(), 0, driv_len + 1);
++ if (!driver) {
++ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len));
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++ _XReadPad(dpy, driver, driv_len);
++ HeapFree(GetProcessHeap(), 0, driver); /* we don't need the driver */
++
++ /* read out device */
++ *device = HeapAlloc(GetProcessHeap(), 0, dev_len + 1);
++ if (!*device) {
++ _XEatData(dpy, XALIGN(dev_len));
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++ _XReadPad(dpy, *device, dev_len);
++ (*device)[dev_len] = '\0';
++
++ UnlockDisplay(dpy);
++ SyncHandle();
++
++ return True;
++}
++
++static Bool
++DRI2Authenticate(Display *dpy,
++ XID window,
++ uint32_t token)
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ xDRI2AuthenticateReply rep;
++ xDRI2AuthenticateReq *req;
++
++ DRI2CheckExtension(dpy, info, False);
++
++ LockDisplay(dpy);
++ GetReq(DRI2Authenticate, req);
++ req->reqType = info->codes->major_opcode;
++ req->dri2ReqType = X_DRI2Authenticate;
++ req->window = window;
++ req->magic = token;
++ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++ UnlockDisplay(dpy);
++ SyncHandle();
++
++ return rep.authenticated ? True : False;
++}
++
++BOOL
++DRI2FallbackOpen(Display *dpy, int screen, int *device_fd)
++{
++ char *device;
++ int fd;
++ Window root = RootWindow(dpy, screen);
++ drm_auth_t auth;
++
++ if (!DRI2Connect(dpy, root, DRI2DriverDRI, &device))
++ return FALSE;
++
++ fd = open(device, O_RDWR);
++ HeapFree(GetProcessHeap(), 0, device);
++ if (fd < 0)
++ return FALSE;
++
++ if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth) != 0) {
++ close(fd);
++ return FALSE;
++ }
++
++ if (!DRI2Authenticate(dpy, root, auth.magic)) {
++ close(fd);
++ return FALSE;
++ }
++
++ *device_fd = fd;
++
++ return TRUE;
++}
++
++#endif
++
++
++BOOL
++DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height, int stride, int depth, int bpp, Pixmap *pixmap)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ Window root = RootWindow(dpy, screen);
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++
++ cookie = xcb_dri3_pixmap_from_buffer_checked(xcb_connection,
++ (*pixmap = xcb_generate_id(xcb_connection)),
++ root,
++ 0,
++ width, height, stride,
++ depth, bpp, fd);
++ error = xcb_request_check(xcb_connection, cookie); /* performs a flush */
++ if (error) {
++ ERR("Error using DRI3 to convert a DmaBufFd to pixmap\n");
++ return FALSE;
++ }
++ return TRUE;
++}
++
++BOOL
++DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height, int *stride, int *depth, int *bpp)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
++ xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
++
++ bp_cookie = xcb_dri3_buffer_from_pixmap(xcb_connection, pixmap);
++ bp_reply = xcb_dri3_buffer_from_pixmap_reply(xcb_connection, bp_cookie, NULL);
++ if (!bp_reply)
++ return FALSE;
++ *fd = xcb_dri3_buffer_from_pixmap_reply_fds(xcb_connection, bp_reply)[0];
++ *width = bp_reply->width;
++ *height = bp_reply->height;
++ *stride = bp_reply->stride;
++ *depth = bp_reply->depth;
++ *bpp = bp_reply->depth;
++ return TRUE;
++}
++
++struct PRESENTPriv {
++ xcb_connection_t *xcb_connection;
++ xcb_connection_t *xcb_connection_bis; /* to avoid libxcb thread bugs, use a different connection to present pixmaps */
++ XID window;
++ uint64_t last_msc;
++ uint64_t last_target;
++ uint32_t last_serial_given;
++ xcb_special_event_t *special_event;
++ PRESENTPixmapPriv *first_present_priv;
++ int pixmap_present_pending;
++ BOOL notify_with_serial_pending;
++ pthread_mutex_t mutex_present; /* protect readind/writing present_priv things */
++ pthread_mutex_t mutex_xcb_wait;
++ BOOL xcb_wait;
++};
++
++struct PRESENTPixmapPriv {
++ PRESENTpriv *present_priv;
++ Pixmap pixmap;
++ BOOL released;
++ unsigned int width;
++ unsigned int height;
++ unsigned int depth;
++ BOOL present_complete_pending;
++ uint32_t serial;
++#ifdef D3DADAPTER9_DRI2
++ struct {
++ BOOL is_dri2;
++ struct DRI2priv *dri2_priv;
++ GLuint fbo_read;
++ GLuint fbo_write;
++ GLuint texture_read;
++ GLuint texture_write;
++ } dri2_info;
++#endif
++ BOOL last_present_was_flip;
++ PRESENTPixmapPriv *next;
++};
++
++static PRESENTPixmapPriv *PRESENTFindPixmapPriv(PRESENTpriv *present_priv, uint32_t serial)
++{
++ PRESENTPixmapPriv *current = present_priv->first_present_priv;
++
++ while (current) {
++ if (current->serial == serial)
++ return current;
++ current = current->next;
++ }
++ return NULL;
++}
++
++static void PRESENThandle_events(PRESENTpriv *present_priv, xcb_present_generic_event_t *ge)
++{
++ PRESENTPixmapPriv *present_pixmap_priv = NULL;
++
++ switch (ge->evtype) {
++ case XCB_PRESENT_COMPLETE_NOTIFY: {
++ xcb_present_complete_notify_event_t *ce = (void *) ge;
++ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC) {
++ if (ce->serial)
++ present_priv->notify_with_serial_pending = FALSE;
++ free(ce);
++ return;
++ }
++ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ce->serial);
++ if (!present_pixmap_priv || ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
++ ERR("FATAL ERROR: PRESENT handling failed\n");
++ free(ce);
++ return;
++ }
++ present_pixmap_priv->present_complete_pending = FALSE;
++ switch (ce->mode) {
++ case XCB_PRESENT_COMPLETE_MODE_FLIP:
++ present_pixmap_priv->last_present_was_flip = TRUE;
++ break;
++ case XCB_PRESENT_COMPLETE_MODE_COPY:
++ present_pixmap_priv->last_present_was_flip = FALSE;
++ break;
++ }
++ present_priv->pixmap_present_pending--;
++ present_priv->last_msc = ce->msc;
++ break;
++ }
++ case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
++ xcb_present_idle_notify_event_t *ie = (void *) ge;
++ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ie->serial);
++ if (!present_pixmap_priv || present_pixmap_priv->pixmap != ie->pixmap) {
++ ERR("FATAL ERROR: PRESENT handling failed\n");
++ free(ie);
++ return;
++ }
++ present_pixmap_priv->released = TRUE;
++ break;
++ }
++ }
++ free(ge);
++}
++
++static void PRESENTflush_events(PRESENTpriv *present_priv, BOOL assert_no_other_thread_waiting)
++{
++ xcb_generic_event_t *ev;
++
++ if ((present_priv->xcb_wait && !assert_no_other_thread_waiting) || /* don't steal events to someone waiting */
++ !present_priv->special_event)
++ return;
++
++ while ((ev = xcb_poll_for_special_event(present_priv->xcb_connection, present_priv->special_event)) != NULL) {
++ PRESENThandle_events(present_priv, (void *) ev);
++ }
++}
++
++static BOOL PRESENTwait_events(PRESENTpriv *present_priv, BOOL allow_other_threads)
++{
++ xcb_generic_event_t *ev;
++
++ if (allow_other_threads) {
++ present_priv->xcb_wait = TRUE;
++ pthread_mutex_lock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ }
++ ev = xcb_wait_for_special_event(present_priv->xcb_connection, present_priv->special_event);
++ if (allow_other_threads) {
++ pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_lock(&present_priv->mutex_present);
++ present_priv->xcb_wait = FALSE;
++ }
++ if (!ev) {
++ ERR("FATAL error: xcb had an error\n");
++ return FALSE;
++ }
++
++ PRESENThandle_events(present_priv, (void *) ev);
++ return TRUE;
++}
++
++static struct xcb_connection_t *
++create_xcb_connection(Display *dpy)
++{
++ int screen_num = DefaultScreen(dpy);
++ xcb_connection_t *ret;
++ xcb_xfixes_query_version_cookie_t cookie;
++ xcb_xfixes_query_version_reply_t *rep;
++
++ ret = xcb_connect(DisplayString(dpy), &screen_num);
++ cookie = xcb_xfixes_query_version_unchecked(ret, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
++ rep = xcb_xfixes_query_version_reply(ret, cookie, NULL);
++ if (rep)
++ free(rep);
++ return ret;
++}
++
++BOOL
++PRESENTInit(Display *dpy, PRESENTpriv **present_priv)
++{
++ *present_priv = (PRESENTpriv *) calloc(1, sizeof(PRESENTpriv));
++ if (!*present_priv) {
++ return FALSE;
++ }
++ (*present_priv)->xcb_connection = create_xcb_connection(dpy);
++ (*present_priv)->xcb_connection_bis = create_xcb_connection(dpy);
++ pthread_mutex_init(&(*present_priv)->mutex_present, NULL);
++ pthread_mutex_init(&(*present_priv)->mutex_xcb_wait, NULL);
++ return TRUE;
++}
++
++static void PRESENTForceReleases(PRESENTpriv *present_priv)
++{
++ PRESENTPixmapPriv *current = NULL;
++
++ if (!present_priv->window)
++ return;
++
++ /* There should be no other thread listening for events here.
++ * This can happen when hDestWindowOverride changes without reset.
++ * This case should never happen, but can happen in theory.*/
++ if (present_priv->xcb_wait) {
++ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 0, 0, 0, 0);
++ xcb_flush(present_priv->xcb_connection);
++ pthread_mutex_lock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
++ /* the problem here is that we don't have access to the event the other thread got.
++ * It is either presented event, idle event or notify event.
++ */
++ while (present_priv->pixmap_present_pending >= 2)
++ PRESENTwait_events(present_priv, FALSE);
++ PRESENTflush_events(present_priv, TRUE);
++ /* Remaining events to come can be a pair of present/idle,
++ * or an idle, or nothing. To be sure we are after all pixmaps
++ * have been presented, add an event to the queue that can only
++ * be after the present event, then if we receive an event more,
++ * we are sure all pixmaps were presented */
++ present_priv->notify_with_serial_pending = TRUE;
++ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 1, present_priv->last_target + 5, 0, 0);
++ xcb_flush(present_priv->xcb_connection);
++ while (present_priv->notify_with_serial_pending)
++ PRESENTwait_events(present_priv, FALSE);
++ /* Now we are sure we are not expecting any new event */
++ } else {
++ while (present_priv->pixmap_present_pending) /* wait all sent pixmaps are presented */
++ PRESENTwait_events(present_priv, FALSE);
++ PRESENTflush_events(present_priv, TRUE); /* may be remaining idle event */
++ /* Since idle events are send with the complete events when it is not flips,
++ * we are not expecting any new event here */
++ }
++
++ current = present_priv->first_present_priv;
++ while (current) {
++ if (!current->released) {
++ if (!current->last_present_was_flip && !present_priv->xcb_wait) {
++ ERR("ERROR: a pixmap seems not released by PRESENT for no reason. Code bug.\n");
++ } else {
++ /* Present the same pixmap with a non-valid part to force the copy mode and the releases */
++ xcb_xfixes_region_t valid, update;
++ xcb_rectangle_t rect_update;
++ rect_update.x = 0;
++ rect_update.y = 0;
++ rect_update.width = 8;
++ rect_update.height = 1;
++ valid = xcb_generate_id(present_priv->xcb_connection);
++ update = xcb_generate_id(present_priv->xcb_connection);
++ xcb_xfixes_create_region(present_priv->xcb_connection, valid, 1, &rect_update);
++ xcb_xfixes_create_region(present_priv->xcb_connection, update, 1, &rect_update);
++ /* here we know the pixmap has been presented. Thus if it is on screen,
++ * the following request can only make it released by the server if it is not */
++ xcb_present_pixmap(present_priv->xcb_connection, present_priv->window,
++ current->pixmap, 0, valid, update, 0, 0, None, None,
++ None, XCB_PRESENT_OPTION_COPY | XCB_PRESENT_OPTION_ASYNC, 0, 0, 0, 0, NULL);
++ xcb_flush(present_priv->xcb_connection);
++ PRESENTwait_events(present_priv, FALSE); /* by assumption this can only be idle event */
++ PRESENTflush_events(present_priv, TRUE); /* Shoudln't be needed */
++ }
++ }
++ current = current->next;
++ }
++ /* Now all pixmaps are released (possibility if xcb_wait is true that one is not aware yet),
++ * and we don't expect any new Present event to come from Xserver */
++}
++
++static void PRESENTFreeXcbQueue(PRESENTpriv *present_priv)
++{
++ if (present_priv->window) {
++ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event);
++ present_priv->last_msc = 0;
++ present_priv->last_target = 0;
++ present_priv->special_event = NULL;
++ }
++}
++
++static BOOL PRESENTPrivChangeWindow(PRESENTpriv *present_priv, XID window)
++{
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++ xcb_present_event_t eid;
++
++ PRESENTForceReleases(present_priv);
++ PRESENTFreeXcbQueue(present_priv);
++ present_priv->window = window;
++
++ if (window) {
++ cookie = xcb_present_select_input_checked(present_priv->xcb_connection,
++ (eid = xcb_generate_id(present_priv->xcb_connection)),
++ window,
++ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|
++ XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
++ present_priv->special_event = xcb_register_for_special_xge(present_priv->xcb_connection,
++ &xcb_present_id,
++ eid, NULL);
++ error = xcb_request_check(present_priv->xcb_connection, cookie); /* performs a flush */
++ if (error || !present_priv->special_event) {
++ ERR("FAILED to use the X PRESENT extension. Was the destination a window ?\n");
++ if (present_priv->special_event)
++ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event);
++ present_priv->special_event = NULL;
++ present_priv->window = 0;
++ }
++ }
++ return (present_priv->window != 0);
++}
++
++/* Destroy the content, except the link and the struct mem */
++static void
++PRESENTDestroyPixmapContent(Display *dpy, PRESENTPixmapPriv *present_pixmap)
++{
++ XFreePixmap(dpy, present_pixmap->pixmap);
++#ifdef D3DADAPTER9_DRI2
++ if (present_pixmap->dri2_info.is_dri2) {
++ struct DRI2priv *dri2_priv = present_pixmap->dri2_info.dri2_priv;
++ EGLenum current_api;
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) {
++ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_read);
++ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_write);
++ glDeleteTextures(1, &present_pixmap->dri2_info.texture_read);
++ glDeleteTextures(1, &present_pixmap->dri2_info.texture_write);
++ } else {
++ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
++ }
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglBindAPI(current_api);
++ }
++#endif
++}
++
++void
++PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv)
++{
++ PRESENTPixmapPriv *current = NULL;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ PRESENTForceReleases(present_priv);
++
++ current = present_priv->first_present_priv;
++ while (current) {
++ PRESENTPixmapPriv *next = current->next;
++ PRESENTDestroyPixmapContent(dpy, current);
++ free(current);
++ current = next;
++ }
++
++ PRESENTFreeXcbQueue(present_priv);
++
++ xcb_disconnect(present_priv->xcb_connection);
++ xcb_disconnect(present_priv->xcb_connection_bis);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ pthread_mutex_destroy(&present_priv->mutex_present);
++ pthread_mutex_destroy(&present_priv->mutex_xcb_wait);
++
++ free(present_priv);
++}
++
++BOOL
++PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv)
++{
++ xcb_get_geometry_cookie_t cookie;
++ xcb_get_geometry_reply_t *reply;
++
++ cookie = xcb_get_geometry(present_priv->xcb_connection, pixmap);
++ reply = xcb_get_geometry_reply(present_priv->xcb_connection, cookie, NULL);
++
++ if (!reply)
++ return FALSE;
++
++ *present_pixmap_priv = (PRESENTPixmapPriv *) calloc(1, sizeof(PRESENTPixmapPriv));
++ if (!*present_pixmap_priv) {
++ free(reply);
++ return FALSE;
++ }
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ (*present_pixmap_priv)->released = TRUE;
++ (*present_pixmap_priv)->pixmap = pixmap;
++ (*present_pixmap_priv)->present_priv = present_priv;
++ (*present_pixmap_priv)->next = present_priv->first_present_priv;
++ (*present_pixmap_priv)->width = reply->width;
++ (*present_pixmap_priv)->height = reply->height;
++ (*present_pixmap_priv)->depth = reply->depth;
++#ifdef D3DADAPTER9_DRI2
++ (*present_pixmap_priv)->dri2_info.is_dri2 = FALSE;
++#endif
++ free(reply);
++
++ present_priv->last_serial_given++;
++ (*present_pixmap_priv)->serial = present_priv->last_serial_given;
++ present_priv->first_present_priv = *present_pixmap_priv;
++
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++#ifdef D3DADAPTER9_DRI2
++
++BOOL
++DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *dri2_priv,
++ int fd, int width, int height, int stride, int depth,
++ int bpp, PRESENTPixmapPriv **present_pixmap_priv)
++{
++ Window root = RootWindow(dri2_priv->dpy, DefaultScreen(dri2_priv->dpy));
++ Pixmap pixmap;
++ EGLImageKHR image;
++ GLuint texture_read, texture_write, fbo_read, fbo_write;
++ EGLint attribs[] = {
++ EGL_WIDTH, 0,
++ EGL_HEIGHT, 0,
++ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
++ EGL_DMA_BUF_PLANE0_FD_EXT, 0,
++ EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
++ EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
++ EGL_NONE
++ };
++ EGLenum current_api;
++ int status;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ pixmap = XCreatePixmap(dri2_priv->dpy, root, width, height, 24);
++ if (!pixmap)
++ goto fail;
++
++ attribs[1] = width;
++ attribs[3] = height;
++ attribs[7] = fd;
++ attribs[11] = stride;
++
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++
++ /* We bind the dma-buf to a EGLImage, then to a texture, and then to a fbo.
++ * Note that we can delete the EGLImage, but we shouldn't delete the texture,
++ * else the fbo is invalid */
++
++ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display,
++ EGL_NO_CONTEXT,
++ EGL_LINUX_DMA_BUF_EXT,
++ NULL, attribs);
++
++ if (image == EGL_NO_IMAGE_KHR)
++ goto fail;
++ close(fd);
++
++ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) {
++ glGenTextures(1, &texture_read);
++ glBindTexture(GL_TEXTURE_2D, texture_read);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image);
++ glGenFramebuffers(1, &fbo_read);
++ glBindFramebuffer(GL_FRAMEBUFFER, fbo_read);
++ glFramebufferTexture2D(GL_FRAMEBUFFER,
++ GL_COLOR_ATTACHMENT0,
++ GL_TEXTURE_2D, texture_read,
++ 0);
++ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
++ if (status != GL_FRAMEBUFFER_COMPLETE)
++ goto fail;
++ glBindTexture(GL_TEXTURE_2D, 0);
++ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image);
++
++ /* We bind a newly created pixmap (to which we want to copy the content)
++ * to an EGLImage, then to a texture, then to a fbo. */
++ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display,
++ dri2_priv->context,
++ EGL_NATIVE_PIXMAP_KHR,
++ (void *)pixmap, NULL);
++ if (image == EGL_NO_IMAGE_KHR)
++ goto fail;
++
++ glGenTextures(1, &texture_write);
++ glBindTexture(GL_TEXTURE_2D, texture_write);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image);
++ glGenFramebuffers(1, &fbo_write);
++ glBindFramebuffer(GL_FRAMEBUFFER, fbo_write);
++ glFramebufferTexture2D(GL_FRAMEBUFFER,
++ GL_COLOR_ATTACHMENT0,
++ GL_TEXTURE_2D, texture_write,
++ 0);
++ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
++ if (status != GL_FRAMEBUFFER_COMPLETE)
++ goto fail;
++ glBindTexture(GL_TEXTURE_2D, 0);
++ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image);
++ } else {
++ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
++ }
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++
++ *present_pixmap_priv = (PRESENTPixmapPriv *) calloc(1, sizeof(PRESENTPixmapPriv));
++ if (!*present_pixmap_priv) {
++ goto fail;
++ }
++
++ (*present_pixmap_priv)->released = TRUE;
++ (*present_pixmap_priv)->pixmap = pixmap;
++ (*present_pixmap_priv)->present_priv = present_priv;
++ (*present_pixmap_priv)->next = present_priv->first_present_priv;
++ (*present_pixmap_priv)->width = width;
++ (*present_pixmap_priv)->height = height;
++ (*present_pixmap_priv)->depth = depth;
++ (*present_pixmap_priv)->dri2_info.is_dri2 = TRUE;
++ (*present_pixmap_priv)->dri2_info.dri2_priv = dri2_priv;
++ (*present_pixmap_priv)->dri2_info.fbo_read = fbo_read;
++ (*present_pixmap_priv)->dri2_info.fbo_write = fbo_write;
++ (*present_pixmap_priv)->dri2_info.texture_read = texture_read;
++ (*present_pixmap_priv)->dri2_info.texture_write = texture_write;
++
++ present_priv->last_serial_given++;
++ (*present_pixmap_priv)->serial = present_priv->last_serial_given;
++ present_priv->first_present_priv = *present_pixmap_priv;
++
++ eglBindAPI(current_api);
++
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++fail:
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglBindAPI(current_api);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++}
++
++#endif
++
++BOOL
++PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++ PRESENTPixmapPriv *current;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) {
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++
++ if (present_priv->first_present_priv == present_pixmap_priv) {
++ present_priv->first_present_priv = present_pixmap_priv->next;
++ goto free_priv;
++ }
++
++ current = present_priv->first_present_priv;
++ while (current->next != present_pixmap_priv)
++ current = current->next;
++ current->next = present_pixmap_priv->next;
++free_priv:
++ PRESENTDestroyPixmapContent(dpy, present_pixmap_priv);
++ free(present_pixmap_priv);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++BOOL
++PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++
++ uint32_t v = 0;
++ xcb_gcontext_t gc;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ if (!present_priv->window) {
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++
++ xcb_create_gc(present_priv->xcb_connection,
++ (gc = xcb_generate_id(present_priv->xcb_connection)),
++ present_priv->window,
++ XCB_GC_GRAPHICS_EXPOSURES,
++ &v);
++ cookie = xcb_copy_area_checked(present_priv->xcb_connection,
++ present_priv->window,
++ present_pixmap_priv->pixmap,
++ gc,
++ 0, 0, 0, 0,
++ present_pixmap_priv->width,
++ present_pixmap_priv->height);
++ error = xcb_request_check(present_priv->xcb_connection, cookie);
++ xcb_free_gc(present_priv->xcb_connection, gc);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return (error != NULL);
++}
++
++BOOL
++PRESENTPixmap(Display *dpy, XID window,
++ PRESENTPixmapPriv *present_pixmap_priv, D3DPRESENT_PARAMETERS *pPresentationParameters,
++ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++#ifdef D3DADAPTER9_DRI2
++ struct DRI2priv *dri2_priv = present_pixmap_priv->dri2_info.dri2_priv;
++ EGLenum current_api;
++#endif
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++ int64_t target_msc, presentationInterval;
++ xcb_xfixes_region_t valid, update;
++ int16_t x_off, y_off;
++ uint32_t options = XCB_PRESENT_OPTION_NONE;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ if (window != present_priv->window)
++ PRESENTPrivChangeWindow(present_priv, window);
++
++ if (!window) {
++ ERR("ERROR: Try to Present a pixmap on a NULL window\n");
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++
++ PRESENTflush_events(present_priv, FALSE);
++ if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) {
++ ERR("FATAL ERROR: Trying to Present a pixmap not released\n");
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++#ifdef D3DADAPTER9_DRI2
++ if (present_pixmap_priv->dri2_info.is_dri2) {
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) {
++ glBindFramebuffer(GL_READ_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_read);
++ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_write);
++
++ glBlitFramebuffer(0, 0, present_pixmap_priv->width, present_pixmap_priv->height,
++ 0, 0, present_pixmap_priv->width, present_pixmap_priv->height,
++ GL_COLOR_BUFFER_BIT, GL_NEAREST);
++ glFlush(); /* Perhaps useless */
++ } else {
++ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
++ }
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglBindAPI(current_api);
++ }
++#endif
++ target_msc = present_priv->last_msc;
++ switch(pPresentationParameters->PresentationInterval) {
++ case D3DPRESENT_INTERVAL_DEFAULT:
++ case D3DPRESENT_INTERVAL_ONE:
++ presentationInterval = 1;
++ break;
++ case D3DPRESENT_INTERVAL_TWO:
++ presentationInterval = 2;
++ break;
++ case D3DPRESENT_INTERVAL_THREE:
++ presentationInterval = 3;
++ break;
++ case D3DPRESENT_INTERVAL_FOUR:
++ presentationInterval = 4;
++ break;
++ case D3DPRESENT_INTERVAL_IMMEDIATE:
++ default:
++ presentationInterval = 0;
++ options |= XCB_PRESENT_OPTION_ASYNC;
++ break;
++ }
++ target_msc += presentationInterval * (present_priv->pixmap_present_pending + 1);
++
++ /* Note: PRESENT defines some way to do partial copy:
++ * presentproto:
++ * 'x-off' and 'y-off' define the location in the window where
++ * the 0,0 location of the pixmap will be presented. valid-area
++ * and update-area are relative to the pixmap.
++ */
++ if (!pSourceRect && !pDestRect && !pDirtyRegion) {
++ valid = 0;
++ update = 0;
++ x_off = 0;
++ y_off = 0;
++ } else {
++ xcb_rectangle_t rect_update;
++ xcb_rectangle_t *rect_updates;
++ int i;
++
++ rect_update.x = 0;
++ rect_update.y = 0;
++ rect_update.width = present_pixmap_priv->width;
++ rect_update.height = present_pixmap_priv->height;
++ x_off = 0;
++ y_off = 0;
++ if (pSourceRect) {
++ x_off = -pSourceRect->left;
++ y_off = -pSourceRect->top;
++ rect_update.x = pSourceRect->left;
++ rect_update.y = pSourceRect->top;
++ rect_update.width = pSourceRect->right - pSourceRect->left;
++ rect_update.height = pSourceRect->bottom - pSourceRect->top;
++ }
++ if (pDestRect) {
++ x_off += pDestRect->left;
++ y_off += pDestRect->top;
++ rect_update.width = pDestRect->right - pDestRect->left;
++ rect_update.height = pDestRect->bottom - pDestRect->top;
++ /* Note: the size of pDestRect and pSourceRect are supposed to be the same size
++ * because the driver would have done things to assure that. */
++ }
++ valid = xcb_generate_id(present_priv->xcb_connection_bis);
++ update = xcb_generate_id(present_priv->xcb_connection_bis);
++ xcb_xfixes_create_region(present_priv->xcb_connection_bis, valid, 1, &rect_update);
++ if (pDirtyRegion && pDirtyRegion->rdh.nCount) {
++ rect_updates = (void *) calloc(pDirtyRegion->rdh.nCount, sizeof(xcb_rectangle_t));
++ for (i = 0; i < pDirtyRegion->rdh.nCount; i++)
++ {
++ RECT rc;
++ memcpy(&rc, pDirtyRegion->Buffer + i * sizeof(RECT), sizeof(RECT));
++ rect_update.x = rc.left;
++ rect_update.y = rc.top;
++ rect_update.width = rc.right - rc.left;
++ rect_update.height = rc.bottom - rc.top;
++ memcpy(rect_updates + i * sizeof(xcb_rectangle_t), &rect_update, sizeof(xcb_rectangle_t));
++ }
++ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, pDirtyRegion->rdh.nCount, rect_updates);
++ free(rect_updates);
++ } else
++ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, 1, &rect_update);
++ }
++ if (pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY)
++ options |= XCB_PRESENT_OPTION_COPY;
++ cookie = xcb_present_pixmap_checked(present_priv->xcb_connection_bis,
++ window,
++ present_pixmap_priv->pixmap,
++ present_pixmap_priv->serial,
++ valid, update, x_off, y_off,
++ None, None, None, options,
++ target_msc, 0, 0, 0, NULL);
++ error = xcb_request_check(present_priv->xcb_connection_bis, cookie); /* performs a flush */
++
++ if (update)
++ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, update);
++ if (valid)
++ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, valid);
++
++ if (error) {
++ xcb_get_geometry_cookie_t cookie_geom;
++ xcb_get_geometry_reply_t *reply;
++
++ cookie_geom = xcb_get_geometry(present_priv->xcb_connection_bis, window);
++ reply = xcb_get_geometry_reply(present_priv->xcb_connection_bis, cookie_geom, NULL);
++
++ ERR("Error using PRESENT. Here some debug info\n");
++ if (!reply) {
++ ERR("Error querying window info. Perhaps it doesn't exist anymore\n");
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++ ERR("Pixmap: width=%d, height=%d, depth=%d\n",
++ present_pixmap_priv->width, present_pixmap_priv->height,
++ present_pixmap_priv->depth);
++ ERR("Window: width=%d, height=%d, depth=%d, x=%d, y=%d\n",
++ (int) reply->width, (int) reply->height,
++ (int) reply->depth, (int) reply->x, (int) reply->y);
++ ERR("Present parameter: PresentationInterval=%d, BackBufferCount=%d, Pending presentations=%d\n",
++ pPresentationParameters->PresentationInterval,
++ pPresentationParameters->BackBufferCount,
++ present_priv->pixmap_present_pending
++ );
++ if (present_pixmap_priv->depth != reply->depth)
++ ERR("Depths are different. PRESENT needs the pixmap and the window have same depth\n");
++ free(reply);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++ present_priv->last_target = target_msc;
++ present_priv->pixmap_present_pending++;
++ present_pixmap_priv->present_complete_pending = TRUE;
++ present_pixmap_priv->released = FALSE;
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++BOOL
++PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ PRESENTflush_events(present_priv, FALSE);
++
++ while (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) {
++ /* Note: following if should not happen because we'll never
++ * use two PRESENTWaitPixmapReleased in parallels on same window.
++ * However it would make it work in that case */
++ if (present_priv->xcb_wait) { /* we allow only one thread to dispatch events */
++ pthread_mutex_lock(&present_priv->mutex_xcb_wait);
++ /* here the other thread got an event but hasn't treated it yet */
++ pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ Sleep(10); /* Let it treat the event */
++ pthread_mutex_lock(&present_priv->mutex_present);
++ } else if (!PRESENTwait_events(present_priv, TRUE)) {
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++ }
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++#endif /* defined(SONAME_LIBXEXT) && defined(SONAME_LIBXFIXES) */
+diff --git a/dlls/winex11.drv/dri3.h b/dlls/winex11.drv/dri3.h
+new file mode 100644
+index 0000000..220e1b9
+--- /dev/null
++++ b/dlls/winex11.drv/dri3.h
+@@ -0,0 +1,110 @@
++/*
++ * 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
++
++#if defined(SONAME_LIBXEXT) && defined(SONAME_LIBXFIXES)
++
++#include <X11/extensions/Xfixes.h>
++#include <X11/Xlib.h>
++#include <X11/Xlib-xcb.h>
++#include <xcb/xcb.h>
++#include <xcb/dri3.h>
++#include <xcb/present.h>
++
++BOOL
++DRI3CheckExtension(Display *dpy, int major, int minor);
++
++#ifdef D3DADAPTER9_DRI2
++struct DRI2priv;
++
++BOOL
++DRI2FallbackInit(Display *dpy, struct DRI2priv **priv);
++
++void
++DRI2FallbackDestroy(struct DRI2priv *priv);
++
++BOOL
++DRI2FallbackCheckSupport(Display *dpy);
++#endif
++
++BOOL
++PRESENTCheckExtension(Display *dpy, int major, int minor);
++
++BOOL
++DRI3Open(Display *dpy, int screen, int *device_fd);
++
++#ifdef D3DADAPTER9_DRI2
++BOOL
++DRI2FallbackOpen(Display *dpy, int screen, int *device_fd);
++#endif
++
++BOOL
++DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height, int stride, int depth, int bpp, Pixmap *pixmap);
++
++BOOL
++DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height, int *stride, int *depth, int *bpp);
++
++typedef struct PRESENTPriv PRESENTpriv;
++typedef struct PRESENTPixmapPriv PRESENTPixmapPriv;
++
++BOOL
++PRESENTInit(Display *dpy, PRESENTpriv **present_priv);
++
++/* will clean properly and free all PRESENTPixmapPriv associated to PRESENTpriv.
++ * PRESENTPixmapPriv should not be freed by something else.
++ * If never a PRESENTPixmapPriv has to be destroyed,
++ * please destroy the current PRESENTpriv and create a new one.
++ * This will take care than all pixmaps are released */
++void
++PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv);
++
++BOOL
++PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv);
++
++#ifdef D3DADAPTER9_DRI2
++BOOL
++DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *priv,
++ int fd, int width, int height, int stride, int depth,
++ int bpp, PRESENTPixmapPriv **present_pixmap_priv);
++#endif
++
++BOOL
++PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv);
++
++BOOL
++PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv);
++
++BOOL
++PRESENTPixmap(Display *dpy, XID window,
++ PRESENTPixmapPriv *present_pixmap_priv, D3DPRESENT_PARAMETERS *pPresentationParameters,
++ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion);
++
++BOOL
++PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv);
++
++#endif /* defined(SONAME_LIBXEXT) && defined(SONAME_LIBXFIXES) */
++
++#endif /* __WINE_DRI3_H */
+diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c
+index 6bc4fb3..ddb6c15 100644
+--- a/dlls/winex11.drv/init.c
++++ b/dlls/winex11.drv/init.c
+@@ -365,6 +365,7 @@ static INT X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_d
+ {
+ struct x11drv_escape_get_drawable *data = out_data;
+ data->drawable = physDev->drawable;
++ data->dc_rect = physDev->dc_rect;
+ return TRUE;
+ }
+ break;
+@@ -464,6 +465,21 @@ static struct opengl_funcs * X11DRV_wine_get_wgl_driver( PHYSDEV dev, UINT versi
+ return ret;
+ }
+
++/**********************************************************************
++ * X11DRV_wine_get_d3dadapter_driver
++ */
++static struct d3dadapter_funcs * X11DRV_wine_get_d3dadapter_driver( PHYSDEV dev, UINT version )
++{
++ struct d3dadapter_funcs *ret;
++
++ if (!(ret = get_d3d_dri3_driver( version )))
++ {
++ dev = GET_NEXT_PHYSDEV( dev, wine_get_d3dadapter_driver );
++ ret = dev->funcs->wine_get_d3dadapter_driver( dev, version );
++ }
++ return ret;
++}
++
+
+ static const struct gdi_dc_funcs x11drv_funcs =
+ {
+@@ -594,6 +610,7 @@ static const struct gdi_dc_funcs x11drv_funcs =
+ X11DRV_UnrealizePalette, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ X11DRV_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ X11DRV_wine_get_d3dadapter_driver, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
+index b7ec06e..353412e 100644
+--- a/dlls/winex11.drv/window.c
++++ b/dlls/winex11.drv/window.c
+@@ -1658,6 +1658,7 @@ void CDECL X11DRV_DestroyWindow( HWND hwnd )
+ struct x11drv_win_data *data;
+
+ destroy_gl_drawable( hwnd );
++ destroy_d3dadapter_drawable( hwnd );
+
+ if (!(data = get_win_data( hwnd ))) return;
+
+diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
+index cb4b0bb..322f457 100644
+--- a/dlls/winex11.drv/x11drv.h
++++ b/dlls/winex11.drv/x11drv.h
+@@ -220,6 +220,7 @@ extern BOOL shape_layered_windows DECLSPEC_HIDDEN;
+ extern const struct gdi_dc_funcs *X11DRV_XRender_Init(void) DECLSPEC_HIDDEN;
+
+ extern struct opengl_funcs *get_glx_driver(UINT) DECLSPEC_HIDDEN;
++extern struct d3dadapter_funcs *get_d3d_dri3_driver(UINT) DECLSPEC_HIDDEN;
+
+ /* IME support */
+ extern void IME_SetOpenStatus(BOOL fOpen) DECLSPEC_HIDDEN;
+@@ -292,6 +293,7 @@ struct x11drv_escape_get_drawable
+ Drawable drawable; /* X drawable */
+ Drawable gl_drawable; /* GL drawable */
+ int pixel_format; /* internal GL pixel format */
++ RECT dc_rect; /* DC rectangle relative to drawable */
+ };
+
+ struct x11drv_escape_flush_gl_drawable
+@@ -372,6 +374,7 @@ extern BOOL show_systray DECLSPEC_HIDDEN;
+ extern BOOL grab_pointer DECLSPEC_HIDDEN;
+ extern BOOL grab_fullscreen DECLSPEC_HIDDEN;
+ extern BOOL usexcomposite DECLSPEC_HIDDEN;
++extern BOOL usexfixes DECLSPEC_HIDDEN;
+ extern BOOL managed_mode DECLSPEC_HIDDEN;
+ extern BOOL decorated_mode DECLSPEC_HIDDEN;
+ extern BOOL private_color_map DECLSPEC_HIDDEN;
+@@ -573,6 +576,8 @@ extern void sync_gl_drawable( HWND hwnd, const RECT *visible_rect, const RECT *c
+ extern void set_gl_drawable_parent( HWND hwnd, HWND parent ) DECLSPEC_HIDDEN;
+ extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN;
+
++extern void destroy_d3dadapter_drawable( HWND hwnd ) DECLSPEC_HIDDEN;
++
+ extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN;
+ extern Window init_clip_window(void) DECLSPEC_HIDDEN;
+ extern void update_user_time( Time time ) DECLSPEC_HIDDEN;
+diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
+index 85c69bf..3a8c3a1 100644
+--- a/dlls/winex11.drv/x11drv_main.c
++++ b/dlls/winex11.drv/x11drv_main.c
+@@ -48,6 +48,7 @@
+
+ #include "x11drv.h"
+ #include "xcomposite.h"
++#include "xfixes.h"
+ #include "wine/server.h"
+ #include "wine/debug.h"
+ #include "wine/library.h"
+@@ -65,6 +66,7 @@ Window root_window;
+ BOOL usexvidmode = TRUE;
+ BOOL usexrandr = TRUE;
+ BOOL usexcomposite = TRUE;
++BOOL usexfixes = TRUE;
+ BOOL use_xkb = TRUE;
+ BOOL use_take_focus = TRUE;
+ BOOL use_primary_selection = FALSE;
+@@ -476,6 +478,54 @@ sym_not_found:
+ }
+ #endif /* defined(SONAME_LIBXCOMPOSITE) */
+
++#ifdef SONAME_LIBXFIXES
++
++#define MAKE_FUNCPTR(f) typeof(f) * p##f;
++MAKE_FUNCPTR(XFixesQueryExtension)
++MAKE_FUNCPTR(XFixesQueryVersion)
++MAKE_FUNCPTR(XFixesCreateRegion)
++MAKE_FUNCPTR(XFixesDestroyRegion)
++#undef MAKE_FUNCPTR
++
++int xfixes_event_base;
++int xfixes_error_base;
++
++static void X11DRV_XFixes_Init(void)
++{
++ void *xfixes_handle = wine_dlopen(SONAME_LIBXFIXES, RTLD_NOW, NULL, 0);
++ if (!xfixes_handle)
++ {
++ TRACE("Unable to open %s, XFixes disabled\n", SONAME_LIBXFIXES);
++ usexfixes = 0;
++ return;
++ }
++
++#define LOAD_FUNCPTR(f) \
++ if((p##f = wine_dlsym(xfixes_handle, #f, NULL, 0)) == NULL) \
++ goto sym_not_found;
++ LOAD_FUNCPTR(XFixesQueryExtension)
++ LOAD_FUNCPTR(XFixesQueryVersion)
++ LOAD_FUNCPTR(XFixesCreateRegion)
++ LOAD_FUNCPTR(XFixesDestroyRegion)
++#undef LOAD_FUNCPTR
++
++ if(!pXFixesQueryExtension(gdi_display, &xfixes_event_base,
++ &xfixes_error_base)) {
++ TRACE("XFixes extension could not be queried; disabled\n");
++ wine_dlclose(xfixes_handle, NULL, 0);
++ usexfixes = 0;
++ return;
++ }
++ TRACE("XFixes is up and running error_base = %d\n", xfixes_error_base);
++ return;
++
++sym_not_found:
++ TRACE("Unable to load function pointers from %s, XFixes disabled\n", SONAME_LIBXFIXES);
++ wine_dlclose(xfixes_handle, NULL, 0);
++ usexfixes = 0;
++}
++#endif /* SONAME_LIBXFIXES */
++
+ static void init_visuals( Display *display, int screen )
+ {
+ int count;
+@@ -582,6 +632,9 @@ static BOOL process_attach(void)
+ #ifdef SONAME_LIBXCOMPOSITE
+ X11DRV_XComposite_Init();
+ #endif
++#ifdef SONAME_LIBXFIXES
++ X11DRV_XFixes_Init();
++#endif
+ X11DRV_XInput2_Init();
+
+ #ifdef HAVE_XKB
+diff --git a/dlls/winex11.drv/xfixes.h b/dlls/winex11.drv/xfixes.h
+new file mode 100644
+index 0000000..cc7e287
+--- /dev/null
++++ b/dlls/winex11.drv/xfixes.h
+@@ -0,0 +1,39 @@
++/*
++ * Wine X11DRV XFixes interface
++ *
++ * Copyright 2007 Chris Robinson
++ * 2013 Joakim Sindholt
++ *
++ * 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_XFIXES_H
++#define __WINE_XFIXES_H
++
++#ifndef __WINE_CONFIG_H
++# error You must include config.h to use this header
++#endif
++
++#ifdef SONAME_LIBXFIXES
++
++#include <X11/extensions/Xfixes.h>
++#define MAKE_FUNCPTR(f) extern typeof(f) * p##f DECLSPEC_HIDDEN;
++MAKE_FUNCPTR(XFixesQueryExtension)
++MAKE_FUNCPTR(XFixesQueryVersion)
++MAKE_FUNCPTR(XFixesCreateRegion)
++MAKE_FUNCPTR(XFixesDestroyRegion)
++#undef MAKE_FUNCPTR
++
++#endif /* defined(SONAME_LIBXFIXES) */
++#endif /* __WINE_XFIXES_H */
+diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c
+index bc2ee40..01ed6e8 100644
+--- a/dlls/winex11.drv/xrender.c
++++ b/dlls/winex11.drv/xrender.c
+@@ -2275,6 +2275,7 @@ static const struct gdi_dc_funcs xrender_funcs =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
+ };
+
+diff --git a/include/wine/d3dadapter.h b/include/wine/d3dadapter.h
+new file mode 100644
+index 0000000..6f90338
+--- /dev/null
++++ b/include/wine/d3dadapter.h
+@@ -0,0 +1,42 @@
++/*
++ * d3dadapter display driver definitions
++ *
++ * Copyright (c) 2013 Joakim Sindholt
++ *
++ * 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_D3DADAPTER_H
++#define __WINE_D3DADAPTER_H
++
++#ifndef __WINE_CONFIG_H
++# error You must include config.h to use this header
++#endif
++
++#ifdef SONAME_D3DADAPTER9
++
++#include <d3dadapter/d3dadapter9.h>
++
++#define WINE_D3DADAPTER_DRIVER_VERSION 0
++
++struct d3dadapter_funcs
++{
++ HRESULT (*create_present_group)(const WCHAR *device_name, UINT adapter, HWND focus, D3DPRESENT_PARAMETERS *params, unsigned nparams, ID3DPresentGroup **group);
++ HRESULT (*create_adapter9)(HDC hdc, ID3DAdapter9 **adapter);
++};
++
++#endif /* SONAME_D3DADAPTER9 */
++
++#endif /* __WINE_D3DADAPTER_H */
+diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h
+index 6f67653..d8706d8 100644
+--- a/include/wine/gdi_driver.h
++++ b/include/wine/gdi_driver.h
+@@ -25,6 +25,7 @@
+
+ struct gdi_dc_funcs;
+ struct opengl_funcs;
++struct d3dadapter_funcs;
+
+ typedef struct gdi_physdev
+ {
+@@ -191,6 +192,7 @@ struct gdi_dc_funcs
+ BOOL (*pUnrealizePalette)(HPALETTE);
+ BOOL (*pWidenPath)(PHYSDEV);
+ struct opengl_funcs * (*wine_get_wgl_driver)(PHYSDEV,UINT);
++ struct d3dadapter_funcs * (*wine_get_d3dadapter_driver)(PHYSDEV,UINT);
+
+ /* priority order for the driver on the stack */
+ UINT priority;
+@@ -278,5 +280,6 @@ extern void CDECL __wine_set_visible_region( HDC hdc, HRGN hrgn, const RECT *vis
+ const RECT *device_rect, struct window_surface *surface );
+ extern void CDECL __wine_set_display_driver( HMODULE module );
+ extern struct opengl_funcs * CDECL __wine_get_wgl_driver( HDC hdc, UINT version );
++extern struct d3dadapter_funcs * CDECL __wine_get_d3dadapter_driver( HDC hdc, UINT version );
+
+ #endif /* __WINE_WINE_GDI_DRIVER_H */
+diff --git a/programs/winecfg/resource.h b/programs/winecfg/resource.h
+index 8604fb4..9111d47 100644
+--- a/programs/winecfg/resource.h
++++ b/programs/winecfg/resource.h
+@@ -59,6 +59,7 @@
+ #define IDC_DESKTOP_HEIGHT 1024
+ #define IDC_DESKTOP_SIZE 1025
+ #define IDC_DESKTOP_BY 1026
++#define IDC_ENABLE_NATIVE_D3D9 1027
+
+ /* dll editing */
+ #define IDC_RAD_BUILTIN 1029
+diff --git a/programs/winecfg/winecfg.rc b/programs/winecfg/winecfg.rc
+index 221916b..077e323 100644
+--- a/programs/winecfg/winecfg.rc
++++ b/programs/winecfg/winecfg.rc
+@@ -176,6 +176,9 @@ BEGIN
+ EDITTEXT IDC_DESKTOP_WIDTH,84,68,40,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
+ EDITTEXT IDC_DESKTOP_HEIGHT,137,68,40,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
+
++ GROUPBOX "3D Acceleration",IDC_STATIC,8,180,244,32
++ CONTROL "Prefer native Direct3D 9 (requires Mesa with Nine state tracker)",IDC_ENABLE_NATIVE_D3D9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,196,230,8
++
+ GROUPBOX "Screen resolution",IDC_STATIC,8,95,244,84
+ CONTROL "", IDC_RES_TRACKBAR, "msctls_trackbar32",WS_TABSTOP,12,105,171,15
+ EDITTEXT IDC_RES_DPIEDIT,188,105,23,13,ES_NUMBER|WS_TABSTOP
+diff --git a/programs/winecfg/x11drvdlg.c b/programs/winecfg/x11drvdlg.c
+index 9a14fb6..81d91b8 100644
+--- a/programs/winecfg/x11drvdlg.c
++++ b/programs/winecfg/x11drvdlg.c
+@@ -46,6 +46,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
+ static const WCHAR logpixels_reg[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\','C','u','r','r','e','n','t','\\','S','o','f','t','w','a','r','e','\\','F','o','n','t','s',0};
+ static const WCHAR logpixels[] = {'L','o','g','P','i','x','e','l','s',0};
+
++static const WCHAR d3d9_reg[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','D','i','r','e','c','t','3','D',0};
++static const WCHAR d3d9[] = {'U','s','e','N','a','t','i','v','e',0};
++
+ static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
+ static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0};
+ static const WCHAR explorerW[] = {'E','x','p','l','o','r','e','r',0};
+@@ -67,6 +70,15 @@ static void convert_x11_desktop_key(void)
+ HeapFree(GetProcessHeap(), 0, buf);
+ }
+
++static INT read_Direct3D_reg(void)
++{
++ DWORD useNative;
++ WCHAR *buf = get_reg_keyW(HKEY_CURRENT_USER, d3d9_reg, d3d9, NULL);
++ useNative = buf ? *buf : 0;
++ HeapFree(GetProcessHeap(), 0, buf);
++ return useNative;
++}
++
+ static void update_gui_for_desktop_mode(HWND dialog)
+ {
+ WCHAR *buf, *bufindex;
+@@ -142,6 +154,11 @@ static void init_dialog(HWND dialog)
+ CheckDlgButton(dialog, IDC_ENABLE_DECORATED, BST_UNCHECKED);
+ HeapFree(GetProcessHeap(), 0, buf);
+
++ if (read_Direct3D_reg())
++ CheckDlgButton(dialog, IDC_ENABLE_NATIVE_D3D9, BST_CHECKED);
++ else
++ CheckDlgButton(dialog, IDC_ENABLE_NATIVE_D3D9, BST_UNCHECKED);
++
+ updating_ui = FALSE;
+ }
+
+@@ -233,6 +250,14 @@ static void on_fullscreen_grab_clicked(HWND dialog)
+ set_reg_key(config_key, keypath("X11 Driver"), "GrabFullscreen", "N");
+ }
+
++static void on_enable_native_d3d9_clicked(HWND dialog)
++{
++ if (IsDlgButtonChecked(dialog, IDC_ENABLE_NATIVE_D3D9) == BST_CHECKED)
++ set_reg_key_dwordW(HKEY_CURRENT_USER, d3d9_reg, d3d9, 1);
++ else
++ set_reg_key_dwordW(HKEY_CURRENT_USER, d3d9_reg, d3d9, 0);
++}
++
+ static INT read_logpixels_reg(void)
+ {
+ DWORD dwLogPixels;
+@@ -378,6 +403,7 @@ GraphDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ case IDC_ENABLE_MANAGED: on_enable_managed_clicked(hDlg); break;
+ case IDC_ENABLE_DECORATED: on_enable_decorated_clicked(hDlg); break;
+ case IDC_FULLSCREEN_GRAB: on_fullscreen_grab_clicked(hDlg); break;
++ case IDC_ENABLE_NATIVE_D3D9: on_enable_native_d3d9_clicked(hDlg); break;
+ }
+ break;
+ }
diff --git a/wine/build/patches/wine-d3d9-1.7.52.patch b/wine/build/patches/wine-d3d9-1.7.52.patch
new file mode 100644
index 00000000..3b1ba518
--- /dev/null
+++ b/wine/build/patches/wine-d3d9-1.7.52.patch
@@ -0,0 +1,9951 @@
+diff --git a/MAINTAINERS b/MAINTAINERS
+index c40bb68..9dba0d2 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -40,6 +40,13 @@ F: dlls/x3daudio*/
+ F: dlls/xapofx*/
+ F: dlls/xaudio*/
+
++ARM, ARM64
++M: André Hentschel <nerv@dawncrow.de>
++F: dlls/dbghelp/cpu_arm*
++F: dlls/msvcrt/except_arm.c
++F: dlls/ntdll/signal_arm*
++F: programs/winedbg/be_arm*
++
+ Direct2D
+ M: Henri Verbeet <hverbeet@codeweavers.com>
+ F: dlls/d2d*/
+@@ -92,6 +99,10 @@ MSI installers
+ M: Hans Leidekker <hans@codeweavers.com>
+ F: dlls/msi/
+
++Netstat
++M: André Hentschel <nerv@dawncrow.de>
++F: programs/netstat/
++
+ OLE Typelibs
+ P: Andrew Eikum <aeikum@codeweavers.com>
+ F: dlls/oleaut32/typelib.c
+@@ -100,6 +111,14 @@ Wine server, IPC
+ M: Alexandre Julliard <julliard@winehq.org>
+ F: server/
+
++Winemaker
++M: André Hentschel <nerv@dawncrow.de>
++F: tools/winemaker
++
++WPcap
++M: André Hentschel <nerv@dawncrow.de>
++F: dlls/wpcap/
++
+ VB Script
+ M: Jacek Caban <jacek@codeweavers.com>
+ F: dlls/vbscript/
+diff --git a/configure.ac b/configure.ac
+index c37c491..022bc95 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -65,6 +65,8 @@ AC_ARG_WITH(openal, AS_HELP_STRING([--without-openal],[do not use OpenAL]),
+ AC_ARG_WITH(opencl, AS_HELP_STRING([--without-opencl],[do not use OpenCL]),
+ [if test "x$withval" = "xno"; then ac_cv_header_CL_cl_h=no; ac_cv_header_OpenCL_opencl_h=no; fi])
+ AC_ARG_WITH(opengl, AS_HELP_STRING([--without-opengl],[do not use OpenGL]))
++AC_ARG_WITH(d3dadapter,AS_HELP_STRING([--without-d3dadapter],[do not use native Direct3D]))
++AC_ARG_WITH(d3dadapter-dri2-fallback, AS_HELP_STRING([--without-d3dadapter-dri2-fallback],[add a DRI2 fallback to d3dadapter DRI3 code]))
+ AC_ARG_WITH(osmesa, AS_HELP_STRING([--without-osmesa],[do not use the OSMesa library]))
+ AC_ARG_WITH(oss, AS_HELP_STRING([--without-oss],[do not use the OSS sound support]))
+ AC_ARG_WITH(pcap, AS_HELP_STRING([--without-pcap],[do not use the Packet Capture library]),
+@@ -79,6 +81,8 @@ AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xco
+ [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi])
+ AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]),
+ [if test "x$withval" = "xno"; then ac_cv_header_X11_Xcursor_Xcursor_h=no; fi])
++AC_ARG_WITH(xfixes, AS_HELP_STRING([--without-xfixes],[do not use the Xfixes extension]),
++ [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xfixes_h=no; fi])
+ AC_ARG_WITH(xinerama, AS_HELP_STRING([--without-xinerama],[do not use Xinerama (multi-monitor support)]),
+ [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xinerama_h=no; fi])
+ AC_ARG_WITH(xinput, AS_HELP_STRING([--without-xinput],[do not use the Xinput extension]),
+@@ -378,6 +382,8 @@ AC_CHECK_LIB(ossaudio,_oss_ioctl)
+
+ AC_SUBST(OPENGL_LIBS,"")
+
++AC_SUBST(D3DADAPTER9_LIBS,"")
++
+ dnl **** Check for header files ****
+
+ AC_SYS_LARGEFILE()
+@@ -1107,6 +1113,7 @@ then
+ X11/extensions/XInput2.h \
+ X11/extensions/XShm.h \
+ X11/extensions/Xcomposite.h \
++ X11/extensions/Xfixes.h \
+ X11/extensions/Xinerama.h \
+ X11/extensions/Xrandr.h \
+ X11/extensions/Xrender.h \
+@@ -1222,6 +1229,14 @@ then
+ WINE_NOTICE_WITH(xcomposite,[test "x$ac_cv_lib_soname_Xcomposite" = "x"],
+ [libxcomposite ${notice_platform}development files not found, Xcomposite won't be supported.])
+
++ dnl *** Check for X Fixes extension
++ if test "$ac_cv_header_X11_extensions_Xfixes_h" = "yes"
++ then
++ WINE_CHECK_SONAME(Xfixes,XFixesCreateRegion,,,[$X_LIBS $XLIB $X_EXTRA_LIBS])
++ fi
++ WINE_NOTICE_WITH(xfixes,[test "x$ac_cv_lib_soname_Xfixes" = "x"],
++ [libxfixes ${notice_platform}development files not found, Xfixes won't be supported.])
++
+ dnl *** Check for XICCallback struct
+ AC_CHECK_MEMBERS([XICCallback.callback, XEvent.xcookie],,,
+ [#ifdef HAVE_X11_XLIB_H
+@@ -1264,6 +1279,28 @@ This probably prevents linking to OpenGL. Try deleting the file and restarting c
+ WINE_WARNING_WITH(opengl,[test -n "$opengl_msg"],[$opengl_msg
+ OpenGL and Direct3D won't be supported.])
+
++
++
++ dnl Check for d3dadapter
++ if test "x$with_d3dadapter" != "xno"
++ then
++ D3D_CFLAGS=`pkg-config --cflags d3d`
++ D3D_LIBS=`pkg-config --libs d3d`
++ AC_SUBST(D3D_CFLAGS)
++ AC_SUBST(D3D_LIBS)
++ AC_DEFINE(SONAME_D3DADAPTER9, ["d3dadapter9.so.1"], ["temporary hack"])
++ AC_DEFINE_UNQUOTED(D3D_MODULE_DIR, ["`pkg-config --variable=moduledir d3d`"], ["module dir"])
++ D3DADAPTER9_LIBS="-lxcb -lxcb-dri3 -lxcb-present -lX11-xcb -lxcb-xfixes -lpthread"
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb -lxcb-dri3 -lxcb-present -lX11-xcb -lxcb-xfixes -lpthread"],[D3Dadapter9 requirements not met])
++ if test "x$with_d3dadapter_dri2_fallback" != "xno"
++ then
++ AC_DEFINE(D3DADAPTER9_DRI2, 1, [Whether d3dadapter9 DRI2 fallback is compiled])
++ WINE_CHECK_SONAME(GL,glGenFramebuffers, [D3DADAPTER9_LIBS="-lGL $D3DADAPTER9_LIBS"])
++ WINE_CHECK_SONAME(EGL,eglCreateContext, [D3DADAPTER9_LIBS="-lEGL $D3DADAPTER9_LIBS"])
++ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lEGL -lGL -lxcb -lxcb-dri3 -lxcb-present -lX11-xcb -lxcb-xfixes -lpthread"],[D3Dadapter9 DRI2 fallback requirements not met])
++ fi
++ fi
++
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ else
+ X_CFLAGS=""
+@@ -3460,6 +3497,10 @@ WINE_CONFIG_DLL(xapofx1_1)
+ WINE_CONFIG_DLL(xapofx1_3)
+ WINE_CONFIG_DLL(xapofx1_4)
+ WINE_CONFIG_DLL(xapofx1_5)
++WINE_CONFIG_DLL(xaudio2_3,,[clean])
++WINE_CONFIG_DLL(xaudio2_4,,[clean])
++WINE_CONFIG_DLL(xaudio2_5,,[clean])
++WINE_CONFIG_DLL(xaudio2_6,,[clean])
+ WINE_CONFIG_DLL(xaudio2_7,,[clean])
+ WINE_CONFIG_TEST(dlls/xaudio2_7/tests)
+ WINE_CONFIG_DLL(xaudio2_8)
+diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
+index 2482b85..f988c0e 100644
+--- a/dlls/advapi32/registry.c
++++ b/dlls/advapi32/registry.c
+@@ -23,6 +23,8 @@
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
++#include "config.h"
++
+ #include <stdlib.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+@@ -522,7 +524,7 @@ LSTATUS WINAPI RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD options, REGSAM acc
+ * Unlike RegCreateKeyExA(), this function will not create the key if it
+ * does not exist.
+ */
+-LSTATUS WINAPI RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
++LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey )
+ {
+ OBJECT_ATTRIBUTES attr;
+ STRING nameA;
+@@ -1107,7 +1109,7 @@ LSTATUS WINAPI RegQueryInfoKeyA( HKEY hkey, LPSTR class, LPDWORD class_len, LPDW
+ * Success: ERROR_SUCCESS
+ * Failure: Error code
+ */
+-LSTATUS WINAPI RegCloseKey( HKEY hkey )
++LSTATUS WINAPI DECLSPEC_HOTPATCH RegCloseKey( HKEY hkey )
+ {
+ if (!hkey) return ERROR_INVALID_HANDLE;
+ if (hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
+@@ -1477,8 +1479,8 @@ LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDW
+ * MSDN states that if data is too small it is partially filled. In reality
+ * it remains untouched.
+ */
+-LSTATUS WINAPI RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
+- LPBYTE data, LPDWORD count )
++LSTATUS WINAPI DECLSPEC_HOTPATCH RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved,
++ LPDWORD type, LPBYTE data, LPDWORD count )
+ {
+ NTSTATUS status;
+ ANSI_STRING nameA;
+diff --git a/dlls/comctl32/comctl32.spec b/dlls/comctl32/comctl32.spec
+index 1e92e5f..1a5ab57 100644
+--- a/dlls/comctl32/comctl32.spec
++++ b/dlls/comctl32/comctl32.spec
+@@ -88,6 +88,7 @@
+ 375 stdcall -noname -private StrCSpnIW(wstr wstr)
+ 376 stdcall -noname -private IntlStrEqWorkerA(long str str long)
+ 377 stdcall -noname -private IntlStrEqWorkerW(long wstr wstr long)
++380 stdcall -ordinal LoadIconMetric(ptr wstr long ptr)
+ 381 stdcall -ordinal LoadIconWithScaleDown(ptr wstr long long ptr)
+ 382 stdcall -noname SmoothScrollWindow(ptr)
+ 383 stub -noname DoReaderMode
+diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c
+index e18c27d..6d6b5e4 100644
+--- a/dlls/comctl32/commctrl.c
++++ b/dlls/comctl32/commctrl.c
+@@ -3,6 +3,7 @@
+ *
+ * Copyright 1997 Dimitrie O. Paun
+ * Copyright 1998,2000 Eric Kohl
++ * Copyright 2014-2015 Michael Müller
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+@@ -1641,8 +1642,47 @@ HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnBu
+ /***********************************************************************
+ * LoadIconWithScaleDown [COMCTL32.@]
+ */
+-HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, PCWSTR name, int cx, int cy, HICON *icon)
++HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
+ {
+- FIXME("stub: %p %s %d %d %p\n", hinst, wine_dbgstr_w(name), cx, cy, icon);
+- return E_NOTIMPL;
++ TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
++
++ *icon = NULL;
++
++ if (!name)
++ return E_INVALIDARG;
++
++ *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
++ (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
++ if (!*icon)
++ return HRESULT_FROM_WIN32(GetLastError());
++
++ return S_OK;
++}
++
++/***********************************************************************
++ * LoadIconMetric [COMCTL32.@]
++ */
++HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
++{
++ int cx, cy;
++
++ TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
++
++ if (size == LIM_SMALL)
++ {
++ cx = GetSystemMetrics(SM_CXSMICON);
++ cy = GetSystemMetrics(SM_CYSMICON);
++ }
++ else if (size == LIM_LARGE)
++ {
++ cx = GetSystemMetrics(SM_CXICON);
++ cy = GetSystemMetrics(SM_CYICON);
++ }
++ else
++ {
++ *icon = NULL;
++ return E_INVALIDARG;
++ }
++
++ return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
+ }
+diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c
+index 280b46c..ffd0dca 100644
+--- a/dlls/comctl32/tests/misc.c
++++ b/dlls/comctl32/tests/misc.c
+@@ -20,6 +20,7 @@
+
+ #include <stdio.h>
+ #include <windows.h>
++#include <commctrl.h>
+
+ #include "wine/test.h"
+ #include "v6util.h"
+@@ -36,6 +37,18 @@ static BOOL (WINAPI * pStr_SetPtrW)(LPWSTR, LPCWSTR);
+
+ static HMODULE hComctl32 = 0;
+
++static char testicon_data[] =
++{
++ 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x00,
++ 0x20, 0x00, 0x40, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
++ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00,
++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x0b,
++ 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0xde, 0xde, 0xde, 0xff, 0xde, 0xde, 0xde, 0xff, 0xde, 0xde,
++ 0xde, 0xff, 0xde, 0xde, 0xde, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00
++};
++
+ #define COMCTL32_GET_PROC(ordinal, func) \
+ p ## func = (void*)GetProcAddress(hComctl32, (LPSTR)ordinal); \
+ if(!p ## func) { \
+@@ -205,6 +218,145 @@ static void test_TaskDialogIndirect(void)
+ ok(ptr == ptr2, "got wrong pointer for ordinal 345, %p expected %p\n", ptr2, ptr);
+ }
+
++static void test_LoadIconWithScaleDown(void)
++{
++ static const WCHAR nonexisting_fileW[] = {'n','o','n','e','x','i','s','t','i','n','g','.','i','c','o',0};
++ static const WCHAR nonexisting_resourceW[] = {'N','o','n','e','x','i','s','t','i','n','g',0};
++ static const WCHAR prefixW[] = {'I','C','O',0};
++ HRESULT (WINAPI *pLoadIconMetric)(HINSTANCE, const WCHAR *, int, HICON *);
++ HRESULT (WINAPI *pLoadIconWithScaleDown)(HINSTANCE, const WCHAR *, int, int, HICON *);
++ WCHAR tmp_path[MAX_PATH], icon_path[MAX_PATH];
++ ICONINFO info;
++ HMODULE hinst;
++ HANDLE handle;
++ DWORD written;
++ HRESULT hr;
++ BITMAP bmp;
++ HICON icon;
++ void *ptr;
++ int bytes;
++ BOOL res;
++
++ hinst = LoadLibraryA("comctl32.dll");
++ pLoadIconMetric = (void *)GetProcAddress(hinst, "LoadIconMetric");
++ pLoadIconWithScaleDown = (void *)GetProcAddress(hinst, "LoadIconWithScaleDown");
++ if (!pLoadIconMetric || !pLoadIconWithScaleDown)
++ {
++ win_skip("LoadIconMetric or pLoadIconWithScaleDown not exported by name\n");
++ FreeLibrary(hinst);
++ return;
++ }
++
++ GetTempPathW(MAX_PATH, tmp_path);
++ GetTempFileNameW(tmp_path, prefixW, 0, icon_path);
++ handle = CreateFileW(icon_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
++ FILE_ATTRIBUTE_NORMAL, NULL);
++ ok(handle != INVALID_HANDLE_VALUE, "CreateFileW failed with error %u\n", GetLastError());
++ res = WriteFile(handle, testicon_data, sizeof(testicon_data), &written, NULL);
++ ok(res && written == sizeof(testicon_data), "Failed to write icon file\n");
++ CloseHandle(handle);
++
++ /* test ordinals */
++ ptr = GetProcAddress(hinst, (const char *)380);
++ ok(ptr == pLoadIconMetric,
++ "got wrong pointer for ordinal 380, %p expected %p\n", ptr, pLoadIconMetric);
++
++ ptr = GetProcAddress(hinst, (const char *)381);
++ ok(ptr == pLoadIconWithScaleDown,
++ "got wrong pointer for ordinal 381, %p expected %p\n", ptr, pLoadIconWithScaleDown);
++
++ /* invalid arguments */
++ icon = (HICON)0x1234;
++ hr = pLoadIconMetric(NULL, MAKEINTRESOURCEW(IDI_APPLICATION), 0x100, &icon);
++ ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %x\n", hr);
++ ok(icon == NULL, "Expected NULL, got %p\n", icon);
++
++ icon = (HICON)0x1234;
++ hr = pLoadIconMetric(NULL, NULL, LIM_LARGE, &icon);
++ ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %x\n", hr);
++ ok(icon == NULL, "Expected NULL, got %p\n", icon);
++
++ icon = (HICON)0x1234;
++ hr = pLoadIconWithScaleDown(NULL, NULL, 32, 32, &icon);
++ ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %x\n", hr);
++ ok(icon == NULL, "Expected NULL, got %p\n", icon);
++
++ /* non-existing filename */
++ hr = pLoadIconMetric(NULL, nonexisting_fileW, LIM_LARGE, &icon);
++ todo_wine
++ ok(hr == HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND),
++ "Expected HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND), got %x\n", hr);
++
++ hr = pLoadIconWithScaleDown(NULL, nonexisting_fileW, 32, 32, &icon);
++ todo_wine
++ ok(hr == HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND),
++ "Expected HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND), got %x\n", hr);
++
++ /* non-existing resource name */
++ hr = pLoadIconMetric(hinst, nonexisting_resourceW, LIM_LARGE, &icon);
++ ok(hr == HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND),
++ "Expected HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND), got %x\n", hr);
++
++ hr = pLoadIconWithScaleDown(hinst, nonexisting_resourceW, 32, 32, &icon);
++ ok(hr == HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND),
++ "Expected HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND), got %x\n", hr);
++
++ /* load icon using predefined identifier */
++ hr = pLoadIconMetric(NULL, MAKEINTRESOURCEW(IDI_APPLICATION), LIM_SMALL, &icon);
++ ok(hr == S_OK, "Expected S_OK, got %x\n", hr);
++ res = GetIconInfo(icon, &info);
++ ok(res, "Failed to get icon info, error %u\n", GetLastError());
++ bytes = GetObjectA(info.hbmColor, sizeof(bmp), &bmp);
++ ok(bytes > 0, "Failed to get bitmap info for icon\n");
++ ok(bmp.bmWidth == GetSystemMetrics(SM_CXSMICON), "Wrong icon width %d\n", bmp.bmWidth);
++ ok(bmp.bmHeight == GetSystemMetrics(SM_CYSMICON), "Wrong icon height %d\n", bmp.bmHeight);
++ DestroyIcon(icon);
++
++ hr = pLoadIconMetric(NULL, MAKEINTRESOURCEW(IDI_APPLICATION), LIM_LARGE, &icon);
++ ok(hr == S_OK, "Expected S_OK, got %x\n", hr);
++ res = GetIconInfo(icon, &info);
++ ok(res, "Failed to get icon info, error %u\n", GetLastError());
++ bytes = GetObjectA(info.hbmColor, sizeof(bmp), &bmp);
++ ok(bytes > 0, "Failed to get bitmap info for icon\n");
++ ok(bmp.bmWidth == GetSystemMetrics(SM_CXICON), "Wrong icon width %d\n", bmp.bmWidth);
++ ok(bmp.bmHeight == GetSystemMetrics(SM_CYICON), "Wrong icon height %d\n", bmp.bmHeight);
++ DestroyIcon(icon);
++
++ hr = pLoadIconWithScaleDown(NULL, MAKEINTRESOURCEW(IDI_APPLICATION), 42, 42, &icon);
++ ok(hr == S_OK, "Expected S_OK, got %x\n", hr);
++ res = GetIconInfo(icon, &info);
++ ok(res, "Failed to get icon info, error %u\n", GetLastError());
++ bytes = GetObjectA(info.hbmColor, sizeof(bmp), &bmp);
++ ok(bytes > 0, "Failed to get bitmap info for icon\n");
++ ok(bmp.bmWidth == 42, "Wrong icon width %d\n", bmp.bmWidth);
++ ok(bmp.bmHeight == 42, "Wrong icon height %d\n", bmp.bmHeight);
++ DestroyIcon(icon);
++
++ /* load icon from file */
++ hr = pLoadIconMetric(NULL, icon_path, LIM_SMALL, &icon);
++ ok(hr == S_OK, "Expected S_OK, got %x\n", hr);
++ res = GetIconInfo(icon, &info);
++ ok(res, "Failed to get icon info, error %u\n", GetLastError());
++ bytes = GetObjectA(info.hbmColor, sizeof(bmp), &bmp);
++ ok(bytes > 0, "Failed to get bitmap info for icon\n");
++ ok(bmp.bmWidth == GetSystemMetrics(SM_CXSMICON), "Wrong icon width %d\n", bmp.bmWidth);
++ ok(bmp.bmHeight == GetSystemMetrics(SM_CYSMICON), "Wrong icon height %d\n", bmp.bmHeight);
++ DestroyIcon(icon);
++
++ hr = pLoadIconWithScaleDown(NULL, icon_path, 42, 42, &icon);
++ ok(hr == S_OK, "Expected S_OK, got %x\n", hr);
++ res = GetIconInfo(icon, &info);
++ ok(res, "Failed to get icon info, error %u\n", GetLastError());
++ bytes = GetObjectA(info.hbmColor, sizeof(bmp), &bmp);
++ ok(bytes > 0, "Failed to get bitmap info for icon\n");
++ ok(bmp.bmWidth == 42, "Wrong icon width %d\n", bmp.bmWidth);
++ ok(bmp.bmHeight == 42, "Wrong icon height %d\n", bmp.bmHeight);
++ DestroyIcon(icon);
++
++ DeleteFileW(icon_path);
++ FreeLibrary(hinst);
++}
++
+ START_TEST(misc)
+ {
+ ULONG_PTR ctx_cookie;
+@@ -220,6 +372,7 @@ START_TEST(misc)
+ return;
+
+ test_TaskDialogIndirect();
++ test_LoadIconWithScaleDown();
+
+ unload_v6_module(ctx_cookie, hCtx);
+ }
+diff --git a/dlls/crypt32/tests/store.c b/dlls/crypt32/tests/store.c
+index a416a39..a0c209a 100644
+--- a/dlls/crypt32/tests/store.c
++++ b/dlls/crypt32/tests/store.c
+@@ -2203,6 +2203,35 @@ static const BYTE serializedStoreWithCertAndHash[] = {
+ 0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,0x01,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+
++static void delete_test_key(void)
++{
++ HKEY root_key, test_key;
++ static const WCHAR SysCertW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
++ 'S','y','s','t','e','m','C','e','r','t','i','f','i','c','a','t','e','s',0};
++ static const WCHAR WineTestW[] = {'W','i','n','e','T','e','s','t',0};
++ WCHAR subkey_name[32];
++ DWORD num_subkeys, subkey_name_len;
++ int idx;
++
++ if (RegOpenKeyExW(HKEY_CURRENT_USER, SysCertW, 0, KEY_READ, &root_key))
++ return;
++ if (RegOpenKeyExW(root_key, WineTestW, 0, KEY_READ, &test_key))
++ {
++ RegCloseKey(root_key);
++ return;
++ }
++ RegQueryInfoKeyW(test_key, NULL, NULL, NULL, &num_subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
++ for (idx = num_subkeys; idx-- > 0;)
++ {
++ subkey_name_len = sizeof(subkey_name)/sizeof(WCHAR);
++ RegEnumKeyExW(test_key, idx, subkey_name, &subkey_name_len, NULL, NULL, NULL, NULL);
++ RegDeleteKeyW(test_key, subkey_name);
++ }
++ RegCloseKey(test_key);
++ RegDeleteKeyW(root_key, WineTestW);
++ RegCloseKey(root_key);
++}
++
+ static void testAddCertificateLink(void)
+ {
+ BOOL ret;
+@@ -2499,6 +2528,8 @@ static void testAddCertificateLink(void)
+
+ CertFreeCertificateContext(source);
+ CertCloseStore(store1, 0);
++
++ delete_test_key();
+ }
+
+ static DWORD countCertsInStore(HCERTSTORE store)
+diff --git a/dlls/d3d11/d3d11_main.c b/dlls/d3d11/d3d11_main.c
+index 5be4cd0..efc346e 100644
+--- a/dlls/d3d11/d3d11_main.c
++++ b/dlls/d3d11/d3d11_main.c
+@@ -342,8 +342,7 @@ HRESULT WINAPI D3D11CreateDeviceAndSwapChain(IDXGIAdapter *adapter, D3D_DRIVER_T
+ return S_OK;
+
+ cleanup:
+- if (device)
+- ID3D11Device_Release(device);
++ ID3D11Device_Release(device);
+ if (obtained_feature_level)
+ *obtained_feature_level = 0;
+ if (immediate_context)
+diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h
+index 6d9489a..313867e 100644
+--- a/dlls/d3d11/d3d11_private.h
++++ b/dlls/d3d11/d3d11_private.h
+@@ -47,7 +47,7 @@
+
+ struct d3d_device;
+
+-struct d3d10_shader_info
++struct d3d_shader_info
+ {
+ const DWORD *shader_code;
+ struct wined3d_shader_signature *input_signature;
+@@ -240,19 +240,21 @@ HRESULT d3d_vertex_shader_create(struct d3d_device *device, const void *byte_cod
+ struct d3d_vertex_shader **shader) DECLSPEC_HIDDEN;
+ struct d3d_vertex_shader *unsafe_impl_from_ID3D10VertexShader(ID3D10VertexShader *iface) DECLSPEC_HIDDEN;
+
+-/* ID3D10GeometryShader */
+-struct d3d10_geometry_shader
++/* ID3D11GeometryShader, ID3D10GeometryShader */
++struct d3d_geometry_shader
+ {
++ ID3D11GeometryShader ID3D11GeometryShader_iface;
+ ID3D10GeometryShader ID3D10GeometryShader_iface;
+ LONG refcount;
+
+ struct wined3d_private_store private_store;
+ struct wined3d_shader *wined3d_shader;
++ ID3D11Device *device;
+ };
+
+-HRESULT d3d10_geometry_shader_init(struct d3d10_geometry_shader *shader, struct d3d_device *device,
+- const void *byte_code, SIZE_T byte_code_length) DECLSPEC_HIDDEN;
+-struct d3d10_geometry_shader *unsafe_impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface) DECLSPEC_HIDDEN;
++HRESULT d3d_geometry_shader_create(struct d3d_device *device, const void *byte_code, SIZE_T byte_code_length,
++ struct d3d_geometry_shader **shader) DECLSPEC_HIDDEN;
++struct d3d_geometry_shader *unsafe_impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface) DECLSPEC_HIDDEN;
+
+ /* ID3D11PixelShader, ID3D10PixelShader */
+ struct d3d_pixel_shader
+@@ -289,21 +291,22 @@ HRESULT d3d10_blend_state_init(struct d3d10_blend_state *state, struct d3d_devic
+ const D3D10_BLEND_DESC *desc) DECLSPEC_HIDDEN;
+ struct d3d10_blend_state *unsafe_impl_from_ID3D10BlendState(ID3D10BlendState *iface) DECLSPEC_HIDDEN;
+
+-/* ID3D10DepthStencilState */
+-struct d3d10_depthstencil_state
++/* ID3D11DepthStencilState, ID3D10DepthStencilState */
++struct d3d_depthstencil_state
+ {
++ ID3D11DepthStencilState ID3D11DepthStencilState_iface;
+ ID3D10DepthStencilState ID3D10DepthStencilState_iface;
+ LONG refcount;
+
+ struct wined3d_private_store private_store;
+- D3D10_DEPTH_STENCIL_DESC desc;
++ D3D11_DEPTH_STENCIL_DESC desc;
+ struct wine_rb_entry entry;
+- ID3D10Device1 *device;
++ ID3D11Device *device;
+ };
+
+-HRESULT d3d10_depthstencil_state_init(struct d3d10_depthstencil_state *state, struct d3d_device *device,
+- const D3D10_DEPTH_STENCIL_DESC *desc) DECLSPEC_HIDDEN;
+-struct d3d10_depthstencil_state *unsafe_impl_from_ID3D10DepthStencilState(
++HRESULT d3d_depthstencil_state_init(struct d3d_depthstencil_state *state, struct d3d_device *device,
++ const D3D11_DEPTH_STENCIL_DESC *desc) DECLSPEC_HIDDEN;
++struct d3d_depthstencil_state *unsafe_impl_from_ID3D10DepthStencilState(
+ ID3D10DepthStencilState *iface) DECLSPEC_HIDDEN;
+
+ /* ID3D11RasterizerState, ID3D10RasterizerState */
+@@ -377,7 +380,7 @@ struct d3d_device
+
+ struct d3d10_blend_state *blend_state;
+ float blend_factor[4];
+- struct d3d10_depthstencil_state *depth_stencil_state;
++ struct d3d_depthstencil_state *depth_stencil_state;
+ UINT stencil_ref;
+ struct d3d_rasterizer_state *rasterizer_state;
+ };
+diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
+index f56d3a9..79e3ea8 100644
+--- a/dlls/d3d11/device.c
++++ b/dlls/d3d11/device.c
+@@ -215,10 +215,22 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateVertexShader(ID3D11Device *i
+ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateGeometryShader(ID3D11Device *iface, const void *byte_code,
+ SIZE_T byte_code_length, ID3D11ClassLinkage *class_linkage, ID3D11GeometryShader **shader)
+ {
+- FIXME("iface %p, byte_code %p, byte_code_length %lu, class_linkage %p, shader %p stub!\n",
++ struct d3d_device *device = impl_from_ID3D11Device(iface);
++ struct d3d_geometry_shader *object;
++ HRESULT hr;
++
++ TRACE("iface %p, byte_code %p, byte_code_length %lu, class_linkage %p, shader %p.\n",
+ iface, byte_code, byte_code_length, class_linkage, shader);
+
+- return E_NOTIMPL;
++ if (class_linkage)
++ FIXME("Class linkage is not implemented yet.\n");
++
++ if (FAILED(hr = d3d_geometry_shader_create(device, byte_code, byte_code_length, &object)))
++ return hr;
++
++ *shader = &object->ID3D11GeometryShader_iface;
++
++ return S_OK;
+ }
+
+ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateGeometryShaderWithStreamOutput(ID3D11Device *iface,
+@@ -301,9 +313,57 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateBlendState(ID3D11Device *ifa
+ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateDepthStencilState(ID3D11Device *iface,
+ const D3D11_DEPTH_STENCIL_DESC *desc, ID3D11DepthStencilState **depth_stencil_state)
+ {
+- FIXME("iface %p, desc %p, depth_stencil_state %p stub!\n", iface, desc, depth_stencil_state);
++ struct d3d_device *device = impl_from_ID3D11Device(iface);
++ struct d3d_depthstencil_state *object;
++ D3D11_DEPTH_STENCIL_DESC tmp_desc;
++ struct wine_rb_entry *entry;
++ HRESULT hr;
+
+- return E_NOTIMPL;
++ TRACE("iface %p, desc %p, depth_stencil_state %p.\n", iface, desc, depth_stencil_state);
++
++ if (!desc)
++ return E_INVALIDARG;
++
++ /* D3D11_DEPTH_STENCIL_DESC has a hole, which is a problem because we use
++ * it as a key in the rbtree. */
++ memset(&tmp_desc, 0, sizeof(tmp_desc));
++ tmp_desc.DepthEnable = desc->DepthEnable;
++ tmp_desc.DepthWriteMask = desc->DepthWriteMask;
++ tmp_desc.DepthFunc = desc->DepthFunc;
++ tmp_desc.StencilEnable = desc->StencilEnable;
++ tmp_desc.StencilReadMask = desc->StencilReadMask;
++ tmp_desc.StencilWriteMask = desc->StencilWriteMask;
++ tmp_desc.FrontFace = desc->FrontFace;
++ tmp_desc.BackFace = desc->BackFace;
++
++ wined3d_mutex_lock();
++ if ((entry = wine_rb_get(&device->depthstencil_states, &tmp_desc)))
++ {
++ object = WINE_RB_ENTRY_VALUE(entry, struct d3d_depthstencil_state, entry);
++
++ TRACE("Returning existing depthstencil state %p.\n", object);
++ *depth_stencil_state = &object->ID3D11DepthStencilState_iface;
++ ID3D11DepthStencilState_AddRef(*depth_stencil_state);
++ wined3d_mutex_unlock();
++
++ return S_OK;
++ }
++ wined3d_mutex_unlock();
++
++ if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
++ return E_OUTOFMEMORY;
++
++ if (FAILED(hr = d3d_depthstencil_state_init(object, device, &tmp_desc)))
++ {
++ WARN("Failed to initialize depthstencil state, hr %#x.\n", hr);
++ HeapFree(GetProcessHeap(), 0, object);
++ return hr;
++ }
++
++ TRACE("Created depthstencil state %p.\n", object);
++ *depth_stencil_state = &object->ID3D11DepthStencilState_iface;
++
++ return S_OK;
+ }
+
+ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateRasterizerState(ID3D11Device *iface,
+@@ -896,7 +956,7 @@ static void STDMETHODCALLTYPE d3d10_device_GSSetConstantBuffers(ID3D10Device1 *i
+ static void STDMETHODCALLTYPE d3d10_device_GSSetShader(ID3D10Device1 *iface, ID3D10GeometryShader *shader)
+ {
+ struct d3d_device *device = impl_from_ID3D10Device(iface);
+- struct d3d10_geometry_shader *gs = unsafe_impl_from_ID3D10GeometryShader(shader);
++ struct d3d_geometry_shader *gs = unsafe_impl_from_ID3D10GeometryShader(shader);
+
+ TRACE("iface %p, shader %p.\n", iface, shader);
+
+@@ -1598,7 +1658,7 @@ static void STDMETHODCALLTYPE d3d10_device_GSGetConstantBuffers(ID3D10Device1 *i
+ static void STDMETHODCALLTYPE d3d10_device_GSGetShader(ID3D10Device1 *iface, ID3D10GeometryShader **shader)
+ {
+ struct d3d_device *device = impl_from_ID3D10Device(iface);
+- struct d3d10_geometry_shader *shader_impl;
++ struct d3d_geometry_shader *shader_impl;
+ struct wined3d_shader *wined3d_shader;
+
+ TRACE("iface %p, shader %p.\n", iface, shader);
+@@ -2309,26 +2369,16 @@ static HRESULT STDMETHODCALLTYPE d3d10_device_CreateVertexShader(ID3D10Device1 *
+ static HRESULT STDMETHODCALLTYPE d3d10_device_CreateGeometryShader(ID3D10Device1 *iface,
+ const void *byte_code, SIZE_T byte_code_length, ID3D10GeometryShader **shader)
+ {
+- struct d3d_device *This = impl_from_ID3D10Device(iface);
+- struct d3d10_geometry_shader *object;
++ struct d3d_device *device = impl_from_ID3D10Device(iface);
++ struct d3d_geometry_shader *object;
+ HRESULT hr;
+
+ TRACE("iface %p, byte_code %p, byte_code_length %lu, shader %p.\n",
+ iface, byte_code, byte_code_length, shader);
+
+- object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
+- if (!object)
+- return E_OUTOFMEMORY;
+-
+- hr = d3d10_geometry_shader_init(object, This, byte_code, byte_code_length);
+- if (FAILED(hr))
+- {
+- WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
+- HeapFree(GetProcessHeap(), 0, object);
++ if (FAILED(hr = d3d_geometry_shader_create(device, byte_code, byte_code_length, &object)))
+ return hr;
+- }
+
+- TRACE("Created geometry shader %p.\n", object);
+ *shader = &object->ID3D10GeometryShader_iface;
+
+ return S_OK;
+@@ -2412,57 +2462,19 @@ static HRESULT STDMETHODCALLTYPE d3d10_device_CreateDepthStencilState(ID3D10Devi
+ const D3D10_DEPTH_STENCIL_DESC *desc, ID3D10DepthStencilState **depth_stencil_state)
+ {
+ struct d3d_device *device = impl_from_ID3D10Device(iface);
+- struct d3d10_depthstencil_state *object;
+- D3D10_DEPTH_STENCIL_DESC tmp_desc;
+- struct wine_rb_entry *entry;
++ ID3D11DepthStencilState *d3d11_depth_stencil_state;
+ HRESULT hr;
+
+ TRACE("iface %p, desc %p, depth_stencil_state %p.\n", iface, desc, depth_stencil_state);
+
+- if (!desc)
+- return E_INVALIDARG;
+-
+- /* D3D10_DEPTH_STENCIL_DESC has a hole, which is a problem because we use
+- * it as a key in the rbtree. */
+- memset(&tmp_desc, 0, sizeof(tmp_desc));
+- tmp_desc.DepthEnable = desc->DepthEnable;
+- tmp_desc.DepthWriteMask = desc->DepthWriteMask;
+- tmp_desc.DepthFunc = desc->DepthFunc;
+- tmp_desc.StencilEnable = desc->StencilEnable;
+- tmp_desc.StencilReadMask = desc->StencilReadMask;
+- tmp_desc.StencilWriteMask = desc->StencilWriteMask;
+- tmp_desc.FrontFace = desc->FrontFace;
+- tmp_desc.BackFace = desc->BackFace;
+-
+- wined3d_mutex_lock();
+- if ((entry = wine_rb_get(&device->depthstencil_states, &tmp_desc)))
+- {
+- object = WINE_RB_ENTRY_VALUE(entry, struct d3d10_depthstencil_state, entry);
+-
+- TRACE("Returning existing depthstencil state %p.\n", object);
+- *depth_stencil_state = &object->ID3D10DepthStencilState_iface;
+- ID3D10DepthStencilState_AddRef(*depth_stencil_state);
+- wined3d_mutex_unlock();
+-
+- return S_OK;
+- }
+- wined3d_mutex_unlock();
+-
+- object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
+- if (!object)
+- return E_OUTOFMEMORY;
+-
+- if (FAILED(hr = d3d10_depthstencil_state_init(object, device, &tmp_desc)))
+- {
+- WARN("Failed to initialize depthstencil state, hr %#x.\n", hr);
+- HeapFree(GetProcessHeap(), 0, object);
++ if (FAILED(hr = d3d11_device_CreateDepthStencilState(&device->ID3D11Device_iface,
++ (const D3D11_DEPTH_STENCIL_DESC *)desc, &d3d11_depth_stencil_state)))
+ return hr;
+- }
+-
+- TRACE("Created depthstencil state %p.\n", object);
+- *depth_stencil_state = &object->ID3D10DepthStencilState_iface;
+
+- return S_OK;
++ hr = ID3D11DepthStencilState_QueryInterface(d3d11_depth_stencil_state, &IID_ID3D10DepthStencilState,
++ (void **)depth_stencil_state);
++ ID3D11DepthStencilState_Release(d3d11_depth_stencil_state);
++ return hr;
+ }
+
+ static HRESULT STDMETHODCALLTYPE d3d10_device_CreateRasterizerState(ID3D10Device1 *iface,
+@@ -3090,21 +3102,21 @@ static const struct wine_rb_functions d3d10_blend_state_rb_ops =
+ d3d10_blend_state_compare,
+ };
+
+-static int d3d10_depthstencil_state_compare(const void *key, const struct wine_rb_entry *entry)
++static int d3d_depthstencil_state_compare(const void *key, const struct wine_rb_entry *entry)
+ {
+- const D3D10_DEPTH_STENCIL_DESC *ka = key;
+- const D3D10_DEPTH_STENCIL_DESC *kb = &WINE_RB_ENTRY_VALUE(entry,
+- const struct d3d10_depthstencil_state, entry)->desc;
++ const D3D11_DEPTH_STENCIL_DESC *ka = key;
++ const D3D11_DEPTH_STENCIL_DESC *kb = &WINE_RB_ENTRY_VALUE(entry,
++ const struct d3d_depthstencil_state, entry)->desc;
+
+ return memcmp(ka, kb, sizeof(*ka));
+ }
+
+-static const struct wine_rb_functions d3d10_depthstencil_state_rb_ops =
++static const struct wine_rb_functions d3d_depthstencil_state_rb_ops =
+ {
+ d3d_rb_alloc,
+ d3d_rb_realloc,
+ d3d_rb_free,
+- d3d10_depthstencil_state_compare,
++ d3d_depthstencil_state_compare,
+ };
+
+ static int d3d_rasterizer_state_compare(const void *key, const struct wine_rb_entry *entry)
+@@ -3145,7 +3157,7 @@ HRESULT d3d_device_init(struct d3d_device *device, void *outer_unknown)
+ device->blend_factor[2] = 1.0f;
+ device->blend_factor[3] = 1.0f;
+
+- if (wine_rb_init(&device->depthstencil_states, &d3d10_depthstencil_state_rb_ops) == -1)
++ if (wine_rb_init(&device->depthstencil_states, &d3d_depthstencil_state_rb_ops) == -1)
+ {
+ WARN("Failed to initialize depthstencil state rbtree.\n");
+ wine_rb_destroy(&device->blend_states, NULL, NULL);
+diff --git a/dlls/d3d11/shader.c b/dlls/d3d11/shader.c
+index 40dac3d..27083de 100644
+--- a/dlls/d3d11/shader.c
++++ b/dlls/d3d11/shader.c
+@@ -26,7 +26,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d11);
+
+ static HRESULT shdr_handler(const char *data, DWORD data_size, DWORD tag, void *ctx)
+ {
+- struct d3d10_shader_info *shader_info = ctx;
++ struct d3d_shader_info *shader_info = ctx;
+ HRESULT hr;
+
+ switch (tag)
+@@ -53,7 +53,7 @@ static HRESULT shdr_handler(const char *data, DWORD data_size, DWORD tag, void *
+ return S_OK;
+ }
+
+-static HRESULT shader_extract_from_dxbc(const void *dxbc, SIZE_T dxbc_length, struct d3d10_shader_info *shader_info)
++static HRESULT shader_extract_from_dxbc(const void *dxbc, SIZE_T dxbc_length, struct d3d_shader_info *shader_info)
+ {
+ HRESULT hr;
+
+@@ -364,7 +364,7 @@ static HRESULT d3d_vertex_shader_init(struct d3d_vertex_shader *shader, struct d
+ {
+ struct wined3d_shader_signature output_signature;
+ struct wined3d_shader_signature input_signature;
+- struct d3d10_shader_info shader_info;
++ struct d3d_shader_info shader_info;
+ struct wined3d_shader_desc desc;
+ HRESULT hr;
+
+@@ -439,71 +439,182 @@ struct d3d_vertex_shader *unsafe_impl_from_ID3D10VertexShader(ID3D10VertexShader
+ return impl_from_ID3D10VertexShader(iface);
+ }
+
+-static inline struct d3d10_geometry_shader *impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface)
++/* ID3D11GeometryShader methods */
++
++static inline struct d3d_geometry_shader *impl_from_ID3D11GeometryShader(ID3D11GeometryShader *iface)
+ {
+- return CONTAINING_RECORD(iface, struct d3d10_geometry_shader, ID3D10GeometryShader_iface);
++ return CONTAINING_RECORD(iface, struct d3d_geometry_shader, ID3D11GeometryShader_iface);
+ }
+
+-/* IUnknown methods */
+-
+-static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_QueryInterface(ID3D10GeometryShader *iface,
++static HRESULT STDMETHODCALLTYPE d3d11_geometry_shader_QueryInterface(ID3D11GeometryShader *iface,
+ REFIID riid, void **object)
+ {
+- TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
++ struct d3d_geometry_shader *shader = impl_from_ID3D11GeometryShader(iface);
+
+- if (IsEqualGUID(riid, &IID_ID3D10GeometryShader)
+- || IsEqualGUID(riid, &IID_ID3D10DeviceChild)
++ TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
++
++ if (IsEqualGUID(riid, &IID_ID3D11GeometryShader)
++ || IsEqualGUID(riid, &IID_ID3D11DeviceChild)
+ || IsEqualGUID(riid, &IID_IUnknown))
+ {
+- IUnknown_AddRef(iface);
++ ID3D11GeometryShader_AddRef(iface);
+ *object = iface;
+ return S_OK;
+ }
+
+- WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
++ if (IsEqualGUID(riid, &IID_ID3D10GeometryShader)
++ || IsEqualGUID(riid, &IID_ID3D10DeviceChild))
++ {
++ ID3D10GeometryShader_AddRef(&shader->ID3D10GeometryShader_iface);
++ *object = &shader->ID3D10GeometryShader_iface;
++ return S_OK;
++ }
++
++ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+-static ULONG STDMETHODCALLTYPE d3d10_geometry_shader_AddRef(ID3D10GeometryShader *iface)
++static ULONG STDMETHODCALLTYPE d3d11_geometry_shader_AddRef(ID3D11GeometryShader *iface)
+ {
+- struct d3d10_geometry_shader *This = impl_from_ID3D10GeometryShader(iface);
+- ULONG refcount = InterlockedIncrement(&This->refcount);
++ struct d3d_geometry_shader *shader = impl_from_ID3D11GeometryShader(iface);
++ ULONG refcount = InterlockedIncrement(&shader->refcount);
+
+- TRACE("%p increasing refcount to %u\n", This, refcount);
++ TRACE("%p increasing refcount to %u.\n", shader, refcount);
+
+ return refcount;
+ }
+
+-static ULONG STDMETHODCALLTYPE d3d10_geometry_shader_Release(ID3D10GeometryShader *iface)
++static ULONG STDMETHODCALLTYPE d3d11_geometry_shader_Release(ID3D11GeometryShader *iface)
+ {
+- struct d3d10_geometry_shader *This = impl_from_ID3D10GeometryShader(iface);
+- ULONG refcount = InterlockedDecrement(&This->refcount);
++ struct d3d_geometry_shader *shader = impl_from_ID3D11GeometryShader(iface);
++ ULONG refcount = InterlockedDecrement(&shader->refcount);
+
+- TRACE("%p decreasing refcount to %u\n", This, refcount);
++ TRACE("%p decreasing refcount to %u.\n", shader, refcount);
+
+ if (!refcount)
+ {
++ ID3D11Device *device = shader->device;
++
+ wined3d_mutex_lock();
+- wined3d_shader_decref(This->wined3d_shader);
++ wined3d_shader_decref(shader->wined3d_shader);
+ wined3d_mutex_unlock();
++
++ /* Release the device last, it may cause the wined3d device to be
++ * destroyed. */
++ ID3D11Device_Release(device);
+ }
+
+ return refcount;
+ }
+
++static void STDMETHODCALLTYPE d3d11_geometry_shader_GetDevice(ID3D11GeometryShader *iface,
++ ID3D11Device **device)
++{
++ struct d3d_geometry_shader *shader = impl_from_ID3D11GeometryShader(iface);
++
++ TRACE("iface %p, device %p.\n", iface, device);
++
++ *device = shader->device;
++ ID3D11Device_AddRef(*device);
++}
++
++static HRESULT STDMETHODCALLTYPE d3d11_geometry_shader_GetPrivateData(ID3D11GeometryShader *iface,
++ REFGUID guid, UINT *data_size, void *data)
++{
++ struct d3d_geometry_shader *shader = impl_from_ID3D11GeometryShader(iface);
++
++ TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
++
++ return d3d_get_private_data(&shader->private_store, guid, data_size, data);
++}
++
++static HRESULT STDMETHODCALLTYPE d3d11_geometry_shader_SetPrivateData(ID3D11GeometryShader *iface,
++ REFGUID guid, UINT data_size, const void *data)
++{
++ struct d3d_geometry_shader *shader = impl_from_ID3D11GeometryShader(iface);
++
++ TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
++
++ return d3d_set_private_data(&shader->private_store, guid, data_size, data);
++}
++
++static HRESULT STDMETHODCALLTYPE d3d11_geometry_shader_SetPrivateDataInterface(ID3D11GeometryShader *iface,
++ REFGUID guid, const IUnknown *data)
++{
++ struct d3d_geometry_shader *shader = impl_from_ID3D11GeometryShader(iface);
++
++ TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
++
++ return d3d_set_private_data_interface(&shader->private_store, guid, data);
++}
++
++static const struct ID3D11GeometryShaderVtbl d3d11_geometry_shader_vtbl =
++{
++ /* IUnknown methods */
++ d3d11_geometry_shader_QueryInterface,
++ d3d11_geometry_shader_AddRef,
++ d3d11_geometry_shader_Release,
++ /* ID3D11DeviceChild methods */
++ d3d11_geometry_shader_GetDevice,
++ d3d11_geometry_shader_GetPrivateData,
++ d3d11_geometry_shader_SetPrivateData,
++ d3d11_geometry_shader_SetPrivateDataInterface,
++};
++
++/* ID3D10GeometryShader methods */
++
++static inline struct d3d_geometry_shader *impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface)
++{
++ return CONTAINING_RECORD(iface, struct d3d_geometry_shader, ID3D10GeometryShader_iface);
++}
++
++/* IUnknown methods */
++
++static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_QueryInterface(ID3D10GeometryShader *iface,
++ REFIID riid, void **object)
++{
++ struct d3d_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
++
++ TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
++
++ return d3d11_geometry_shader_QueryInterface(&shader->ID3D11GeometryShader_iface, riid, object);
++}
++
++static ULONG STDMETHODCALLTYPE d3d10_geometry_shader_AddRef(ID3D10GeometryShader *iface)
++{
++ struct d3d_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
++
++ TRACE("iface %p.\n", iface);
++
++ return d3d11_geometry_shader_AddRef(&shader->ID3D11GeometryShader_iface);
++}
++
++static ULONG STDMETHODCALLTYPE d3d10_geometry_shader_Release(ID3D10GeometryShader *iface)
++{
++ struct d3d_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
++
++ TRACE("iface %p.\n", iface);
++
++ return d3d11_geometry_shader_Release(&shader->ID3D11GeometryShader_iface);
++}
++
+ /* ID3D10DeviceChild methods */
+
+ static void STDMETHODCALLTYPE d3d10_geometry_shader_GetDevice(ID3D10GeometryShader *iface, ID3D10Device **device)
+ {
+- FIXME("iface %p, device %p stub!\n", iface, device);
++ struct d3d_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
++
++ TRACE("iface %p, device %p.\n", iface, device);
++
++ ID3D11Device_QueryInterface(shader->device, &IID_ID3D10Device, (void **)device);
+ }
+
+ static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_GetPrivateData(ID3D10GeometryShader *iface,
+ REFGUID guid, UINT *data_size, void *data)
+ {
+- struct d3d10_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
++ struct d3d_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
+
+ TRACE("iface %p, guid %s, data_size %p, data %p.\n",
+ iface, debugstr_guid(guid), data_size, data);
+@@ -514,7 +625,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_GetPrivateData(ID3D10Geom
+ static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_SetPrivateData(ID3D10GeometryShader *iface,
+ REFGUID guid, UINT data_size, const void *data)
+ {
+- struct d3d10_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
++ struct d3d_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
+
+ TRACE("iface %p, guid %s, data_size %u, data %p.\n",
+ iface, debugstr_guid(guid), data_size, data);
+@@ -525,7 +636,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_SetPrivateData(ID3D10Geom
+ static HRESULT STDMETHODCALLTYPE d3d10_geometry_shader_SetPrivateDataInterface(ID3D10GeometryShader *iface,
+ REFGUID guid, const IUnknown *data)
+ {
+- struct d3d10_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
++ struct d3d_geometry_shader *shader = impl_from_ID3D10GeometryShader(iface);
+
+ TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+@@ -545,28 +656,29 @@ static const struct ID3D10GeometryShaderVtbl d3d10_geometry_shader_vtbl =
+ d3d10_geometry_shader_SetPrivateDataInterface,
+ };
+
+-static void STDMETHODCALLTYPE d3d10_geometry_shader_wined3d_object_destroyed(void *parent)
++static void STDMETHODCALLTYPE d3d_geometry_shader_wined3d_object_destroyed(void *parent)
+ {
+- struct d3d10_geometry_shader *shader = parent;
++ struct d3d_geometry_shader *shader = parent;
+
+ wined3d_private_store_cleanup(&shader->private_store);
+ HeapFree(GetProcessHeap(), 0, parent);
+ }
+
+-static const struct wined3d_parent_ops d3d10_geometry_shader_wined3d_parent_ops =
++static const struct wined3d_parent_ops d3d_geometry_shader_wined3d_parent_ops =
+ {
+- d3d10_geometry_shader_wined3d_object_destroyed,
++ d3d_geometry_shader_wined3d_object_destroyed,
+ };
+
+-HRESULT d3d10_geometry_shader_init(struct d3d10_geometry_shader *shader, struct d3d_device *device,
++static HRESULT d3d_geometry_shader_init(struct d3d_geometry_shader *shader, struct d3d_device *device,
+ const void *byte_code, SIZE_T byte_code_length)
+ {
+ struct wined3d_shader_signature output_signature;
+ struct wined3d_shader_signature input_signature;
+- struct d3d10_shader_info shader_info;
++ struct d3d_shader_info shader_info;
+ struct wined3d_shader_desc desc;
+ HRESULT hr;
+
++ shader->ID3D11GeometryShader_iface.lpVtbl = &d3d11_geometry_shader_vtbl;
+ shader->ID3D10GeometryShader_iface.lpVtbl = &d3d10_geometry_shader_vtbl;
+ shader->refcount = 1;
+ wined3d_mutex_lock();
+@@ -588,7 +700,7 @@ HRESULT d3d10_geometry_shader_init(struct d3d10_geometry_shader *shader, struct
+ desc.max_version = 4;
+
+ hr = wined3d_shader_create_gs(device->wined3d_device, &desc, shader,
+- &d3d10_geometry_shader_wined3d_parent_ops, &shader->wined3d_shader);
++ &d3d_geometry_shader_wined3d_parent_ops, &shader->wined3d_shader);
+ shader_free_signature(&input_signature);
+ shader_free_signature(&output_signature);
+ if (FAILED(hr))
+@@ -600,10 +712,35 @@ HRESULT d3d10_geometry_shader_init(struct d3d10_geometry_shader *shader, struct
+ }
+ wined3d_mutex_unlock();
+
++ shader->device = &device->ID3D11Device_iface;
++ ID3D11Device_AddRef(shader->device);
++
++ return S_OK;
++}
++
++HRESULT d3d_geometry_shader_create(struct d3d_device *device, const void *byte_code, SIZE_T byte_code_length,
++ struct d3d_geometry_shader **shader)
++{
++ struct d3d_geometry_shader *object;
++ HRESULT hr;
++
++ if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
++ return E_OUTOFMEMORY;
++
++ if (FAILED(hr = d3d_geometry_shader_init(object, device, byte_code, byte_code_length)))
++ {
++ WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
++ HeapFree(GetProcessHeap(), 0, object);
++ return hr;
++ }
++
++ TRACE("Created geometry shader %p.\n", object);
++ *shader = object;
++
+ return S_OK;
+ }
+
+-struct d3d10_geometry_shader *unsafe_impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface)
++struct d3d_geometry_shader *unsafe_impl_from_ID3D10GeometryShader(ID3D10GeometryShader *iface)
+ {
+ if (!iface)
+ return NULL;
+@@ -854,7 +991,7 @@ static HRESULT d3d_pixel_shader_init(struct d3d_pixel_shader *shader, struct d3d
+ {
+ struct wined3d_shader_signature output_signature;
+ struct wined3d_shader_signature input_signature;
+- struct d3d10_shader_info shader_info;
++ struct d3d_shader_info shader_info;
+ struct wined3d_shader_desc desc;
+ HRESULT hr;
+
+diff --git a/dlls/d3d11/state.c b/dlls/d3d11/state.c
+index 1adcdbd..1586067 100644
+--- a/dlls/d3d11/state.c
++++ b/dlls/d3d11/state.c
+@@ -192,56 +192,66 @@ struct d3d10_blend_state *unsafe_impl_from_ID3D10BlendState(ID3D10BlendState *if
+ return impl_from_ID3D10BlendState(iface);
+ }
+
+-static inline struct d3d10_depthstencil_state *impl_from_ID3D10DepthStencilState(ID3D10DepthStencilState *iface)
++/* ID3D11DepthStencilState methods */
++
++static inline struct d3d_depthstencil_state *impl_from_ID3D11DepthStencilState(ID3D11DepthStencilState *iface)
+ {
+- return CONTAINING_RECORD(iface, struct d3d10_depthstencil_state, ID3D10DepthStencilState_iface);
++ return CONTAINING_RECORD(iface, struct d3d_depthstencil_state, ID3D11DepthStencilState_iface);
+ }
+
+-/* IUnknown methods */
+-
+-static HRESULT STDMETHODCALLTYPE d3d10_depthstencil_state_QueryInterface(ID3D10DepthStencilState *iface,
++static HRESULT STDMETHODCALLTYPE d3d11_depthstencil_state_QueryInterface(ID3D11DepthStencilState *iface,
+ REFIID riid, void **object)
+ {
++ struct d3d_depthstencil_state *state = impl_from_ID3D11DepthStencilState(iface);
++
+ TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
+
+- if (IsEqualGUID(riid, &IID_ID3D10DepthStencilState)
+- || IsEqualGUID(riid, &IID_ID3D10DeviceChild)
++ if (IsEqualGUID(riid, &IID_ID3D11DepthStencilState)
++ || IsEqualGUID(riid, &IID_ID3D11DeviceChild)
+ || IsEqualGUID(riid, &IID_IUnknown))
+ {
+- IUnknown_AddRef(iface);
++ ID3D11DepthStencilState_AddRef(iface);
+ *object = iface;
+ return S_OK;
+ }
+
++ if (IsEqualGUID(riid, &IID_ID3D10DepthStencilState)
++ || IsEqualGUID(riid, &IID_ID3D10DeviceChild))
++ {
++ ID3D10DepthStencilState_AddRef(&state->ID3D10DepthStencilState_iface);
++ *object = &state->ID3D10DepthStencilState_iface;
++ return S_OK;
++ }
++
+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
+
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+-static ULONG STDMETHODCALLTYPE d3d10_depthstencil_state_AddRef(ID3D10DepthStencilState *iface)
++static ULONG STDMETHODCALLTYPE d3d11_depthstencil_state_AddRef(ID3D11DepthStencilState *iface)
+ {
+- struct d3d10_depthstencil_state *This = impl_from_ID3D10DepthStencilState(iface);
+- ULONG refcount = InterlockedIncrement(&This->refcount);
++ struct d3d_depthstencil_state *state = impl_from_ID3D11DepthStencilState(iface);
++ ULONG refcount = InterlockedIncrement(&state->refcount);
+
+- TRACE("%p increasing refcount to %u.\n", This, refcount);
++ TRACE("%p increasing refcount to %u.\n", state, refcount);
+
+ return refcount;
+ }
+
+-static ULONG STDMETHODCALLTYPE d3d10_depthstencil_state_Release(ID3D10DepthStencilState *iface)
++static ULONG STDMETHODCALLTYPE d3d11_depthstencil_state_Release(ID3D11DepthStencilState *iface)
+ {
+- struct d3d10_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
++ struct d3d_depthstencil_state *state = impl_from_ID3D11DepthStencilState(iface);
+ ULONG refcount = InterlockedDecrement(&state->refcount);
+
+ TRACE("%p decreasing refcount to %u.\n", state, refcount);
+
+ if (!refcount)
+ {
+- struct d3d_device *device = impl_from_ID3D10Device(state->device);
++ struct d3d_device *device = impl_from_ID3D11Device(state->device);
+ wined3d_mutex_lock();
+ wine_rb_remove(&device->depthstencil_states, &state->desc);
+- ID3D10Device1_Release(state->device);
++ ID3D11Device_Release(state->device);
+ wined3d_private_store_cleanup(&state->private_store);
+ wined3d_mutex_unlock();
+ HeapFree(GetProcessHeap(), 0, state);
+@@ -250,22 +260,124 @@ static ULONG STDMETHODCALLTYPE d3d10_depthstencil_state_Release(ID3D10DepthStenc
+ return refcount;
+ }
+
++static void STDMETHODCALLTYPE d3d11_depthstencil_state_GetDevice(ID3D11DepthStencilState *iface,
++ ID3D11Device **device)
++{
++ struct d3d_depthstencil_state *state = impl_from_ID3D11DepthStencilState(iface);
++
++ TRACE("iface %p, device %p.\n", iface, device);
++
++ *device = state->device;
++ ID3D11Device_AddRef(*device);
++}
++
++static HRESULT STDMETHODCALLTYPE d3d11_depthstencil_state_GetPrivateData(ID3D11DepthStencilState *iface,
++ REFGUID guid, UINT *data_size, void *data)
++{
++ struct d3d_depthstencil_state *state = impl_from_ID3D11DepthStencilState(iface);
++
++ TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
++
++ return d3d_get_private_data(&state->private_store, guid, data_size, data);
++}
++
++static HRESULT STDMETHODCALLTYPE d3d11_depthstencil_state_SetPrivateData(ID3D11DepthStencilState *iface,
++ REFGUID guid, UINT data_size, const void *data)
++{
++ struct d3d_depthstencil_state *state = impl_from_ID3D11DepthStencilState(iface);
++
++ TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
++
++ return d3d_set_private_data(&state->private_store, guid, data_size, data);
++}
++
++static HRESULT STDMETHODCALLTYPE d3d11_depthstencil_state_SetPrivateDataInterface(ID3D11DepthStencilState *iface,
++ REFGUID guid, const IUnknown *data)
++{
++ struct d3d_depthstencil_state *state = impl_from_ID3D11DepthStencilState(iface);
++
++ TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
++
++ return d3d_set_private_data_interface(&state->private_store, guid, data);
++}
++
++static void STDMETHODCALLTYPE d3d11_depthstencil_state_GetDesc(ID3D11DepthStencilState *iface,
++ D3D11_DEPTH_STENCIL_DESC *desc)
++{
++ struct d3d_depthstencil_state *state = impl_from_ID3D11DepthStencilState(iface);
++
++ TRACE("iface %p, desc %p.\n", iface, desc);
++
++ *desc = state->desc;
++}
++
++static const struct ID3D11DepthStencilStateVtbl d3d11_depthstencil_state_vtbl =
++{
++ /* IUnknown methods */
++ d3d11_depthstencil_state_QueryInterface,
++ d3d11_depthstencil_state_AddRef,
++ d3d11_depthstencil_state_Release,
++ /* ID3D11DeviceChild methods */
++ d3d11_depthstencil_state_GetDevice,
++ d3d11_depthstencil_state_GetPrivateData,
++ d3d11_depthstencil_state_SetPrivateData,
++ d3d11_depthstencil_state_SetPrivateDataInterface,
++ /* ID3D11DepthStencilState methods */
++ d3d11_depthstencil_state_GetDesc,
++};
++
++/* ID3D10DepthStencilState methods */
++
++static inline struct d3d_depthstencil_state *impl_from_ID3D10DepthStencilState(ID3D10DepthStencilState *iface)
++{
++ return CONTAINING_RECORD(iface, struct d3d_depthstencil_state, ID3D10DepthStencilState_iface);
++}
++
++/* IUnknown methods */
++
++static HRESULT STDMETHODCALLTYPE d3d10_depthstencil_state_QueryInterface(ID3D10DepthStencilState *iface,
++ REFIID riid, void **object)
++{
++ struct d3d_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
++
++ TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
++
++ return d3d11_depthstencil_state_QueryInterface(&state->ID3D11DepthStencilState_iface, riid, object);
++}
++
++static ULONG STDMETHODCALLTYPE d3d10_depthstencil_state_AddRef(ID3D10DepthStencilState *iface)
++{
++ struct d3d_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
++
++ TRACE("iface %p.\n", iface);
++
++ return d3d11_depthstencil_state_AddRef(&state->ID3D11DepthStencilState_iface);
++}
++
++static ULONG STDMETHODCALLTYPE d3d10_depthstencil_state_Release(ID3D10DepthStencilState *iface)
++{
++ struct d3d_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
++
++ TRACE("iface %p.\n", iface);
++
++ return d3d11_depthstencil_state_Release(&state->ID3D11DepthStencilState_iface);
++}
++
+ /* ID3D10DeviceChild methods */
+
+ static void STDMETHODCALLTYPE d3d10_depthstencil_state_GetDevice(ID3D10DepthStencilState *iface, ID3D10Device **device)
+ {
+- struct d3d10_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
++ struct d3d_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
+
+ TRACE("iface %p, device %p.\n", iface, device);
+
+- *device = (ID3D10Device *)state->device;
+- ID3D10Device_AddRef(*device);
++ ID3D11Device_QueryInterface(state->device, &IID_ID3D10Device, (void **)device);
+ }
+
+ static HRESULT STDMETHODCALLTYPE d3d10_depthstencil_state_GetPrivateData(ID3D10DepthStencilState *iface,
+ REFGUID guid, UINT *data_size, void *data)
+ {
+- struct d3d10_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
++ struct d3d_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
+
+ TRACE("iface %p, guid %s, data_size %p, data %p.\n",
+ iface, debugstr_guid(guid), data_size, data);
+@@ -276,7 +388,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_depthstencil_state_GetPrivateData(ID3D10D
+ static HRESULT STDMETHODCALLTYPE d3d10_depthstencil_state_SetPrivateData(ID3D10DepthStencilState *iface,
+ REFGUID guid, UINT data_size, const void *data)
+ {
+- struct d3d10_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
++ struct d3d_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
+
+ TRACE("iface %p, guid %s, data_size %u, data %p.\n",
+ iface, debugstr_guid(guid), data_size, data);
+@@ -287,7 +399,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_depthstencil_state_SetPrivateData(ID3D10D
+ static HRESULT STDMETHODCALLTYPE d3d10_depthstencil_state_SetPrivateDataInterface(ID3D10DepthStencilState *iface,
+ REFGUID guid, const IUnknown *data)
+ {
+- struct d3d10_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
++ struct d3d_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
+
+ TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+@@ -299,11 +411,11 @@ static HRESULT STDMETHODCALLTYPE d3d10_depthstencil_state_SetPrivateDataInterfac
+ static void STDMETHODCALLTYPE d3d10_depthstencil_state_GetDesc(ID3D10DepthStencilState *iface,
+ D3D10_DEPTH_STENCIL_DESC *desc)
+ {
+- struct d3d10_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
++ struct d3d_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface);
+
+ TRACE("iface %p, desc %p.\n", iface, desc);
+
+- *desc = state->desc;
++ memcpy(desc, &state->desc, sizeof(*desc));
+ }
+
+ static const struct ID3D10DepthStencilStateVtbl d3d10_depthstencil_state_vtbl =
+@@ -321,9 +433,10 @@ static const struct ID3D10DepthStencilStateVtbl d3d10_depthstencil_state_vtbl =
+ d3d10_depthstencil_state_GetDesc,
+ };
+
+-HRESULT d3d10_depthstencil_state_init(struct d3d10_depthstencil_state *state, struct d3d_device *device,
+- const D3D10_DEPTH_STENCIL_DESC *desc)
++HRESULT d3d_depthstencil_state_init(struct d3d_depthstencil_state *state, struct d3d_device *device,
++ const D3D11_DEPTH_STENCIL_DESC *desc)
+ {
++ state->ID3D11DepthStencilState_iface.lpVtbl = &d3d11_depthstencil_state_vtbl;
+ state->ID3D10DepthStencilState_iface.lpVtbl = &d3d10_depthstencil_state_vtbl;
+ state->refcount = 1;
+ wined3d_mutex_lock();
+@@ -339,13 +452,13 @@ HRESULT d3d10_depthstencil_state_init(struct d3d10_depthstencil_state *state, st
+ }
+ wined3d_mutex_unlock();
+
+- state->device = &device->ID3D10Device1_iface;
+- ID3D10Device1_AddRef(state->device);
++ state->device = &device->ID3D11Device_iface;
++ ID3D11Device_AddRef(state->device);
+
+ return S_OK;
+ }
+
+-struct d3d10_depthstencil_state *unsafe_impl_from_ID3D10DepthStencilState(ID3D10DepthStencilState *iface)
++struct d3d_depthstencil_state *unsafe_impl_from_ID3D10DepthStencilState(ID3D10DepthStencilState *iface)
+ {
+ if (!iface)
+ return NULL;
+diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
+index d2deffd..bc44dbd 100644
+--- a/dlls/d3d11/tests/d3d11.c
++++ b/dlls/d3d11/tests/d3d11.c
+@@ -1469,6 +1469,69 @@ static void test_create_shader(void)
+ }
+ }
+
++static void test_create_depthstencil_state(void)
++{
++ ID3D11DepthStencilState *ds_state1, *ds_state2;
++ ID3D10DepthStencilState *d3d10_ds_state;
++ ULONG refcount, expected_refcount;
++ D3D11_DEPTH_STENCIL_DESC ds_desc;
++ ID3D11Device *device, *tmp;
++ HRESULT hr;
++
++ if (!(device = create_device(NULL)))
++ {
++ skip("Failed to create device.\n");
++ return;
++ }
++
++ hr = ID3D11Device_CreateDepthStencilState(device, NULL, &ds_state1);
++ ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
++
++ ds_desc.DepthEnable = TRUE;
++ ds_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
++ ds_desc.DepthFunc = D3D11_COMPARISON_LESS;
++ ds_desc.StencilEnable = FALSE;
++ ds_desc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
++ ds_desc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
++ ds_desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
++ ds_desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
++ ds_desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
++ ds_desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
++ ds_desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
++ ds_desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
++ ds_desc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
++ ds_desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
++
++ expected_refcount = get_refcount((IUnknown *)device) + 1;
++ hr = ID3D11Device_CreateDepthStencilState(device, &ds_desc, &ds_state1);
++ ok(SUCCEEDED(hr), "Failed to create depthstencil state, hr %#x.\n", hr);
++ hr = ID3D11Device_CreateDepthStencilState(device, &ds_desc, &ds_state2);
++ ok(SUCCEEDED(hr), "Failed to create depthstencil state, hr %#x.\n", hr);
++ ok(ds_state1 == ds_state2, "Got different depthstencil state objects.\n");
++ refcount = get_refcount((IUnknown *)device);
++ ok(refcount >= expected_refcount, "Got unexpected refcount %u, expected >= %u.\n", refcount, expected_refcount);
++ tmp = NULL;
++ expected_refcount = refcount + 1;
++ ID3D11DepthStencilState_GetDevice(ds_state1, &tmp);
++ ok(tmp == device, "Got unexpected device %p, expected %p.\n", tmp, device);
++ refcount = get_refcount((IUnknown *)device);
++ ok(refcount == expected_refcount, "Got unexpected refcount %u, expected %u.\n", refcount, expected_refcount);
++ ID3D11Device_Release(tmp);
++
++ hr = ID3D11DepthStencilState_QueryInterface(ds_state1, &IID_ID3D10DepthStencilState, (void **)&d3d10_ds_state);
++ ok(SUCCEEDED(hr) || broken(hr == E_NOINTERFACE) /* Not available on all Windows versions. */,
++ "Depth stencil state should implement ID3D10DepthStencilState.\n");
++ if (SUCCEEDED(hr)) ID3D10DepthStencilState_Release(d3d10_ds_state);
++
++ refcount = ID3D11DepthStencilState_Release(ds_state2);
++ ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
++ refcount = ID3D11DepthStencilState_Release(ds_state1);
++ ok(!refcount, "Got unexpected refcount %u.\n", refcount);
++
++ refcount = ID3D11Device_Release(device);
++ ok(!refcount, "Device has %u references left.\n", refcount);
++}
++
+ static void test_create_rasterizer_state(void)
+ {
+ ID3D11RasterizerState *rast_state1, *rast_state2;
+@@ -1563,5 +1626,6 @@ START_TEST(d3d11)
+ test_create_rendertarget_view();
+ test_create_shader_resource_view();
+ test_create_shader();
++ test_create_depthstencil_state();
+ test_create_rasterizer_state();
+ }
+diff --git a/dlls/d3d9/Makefile.in b/dlls/d3d9/Makefile.in
+index 1c05f5a..92b458d 100644
+--- a/dlls/d3d9/Makefile.in
++++ b/dlls/d3d9/Makefile.in
+@@ -1,10 +1,11 @@
+ MODULE = d3d9.dll
+ IMPORTLIB = d3d9
+-IMPORTS = dxguid uuid wined3d
++IMPORTS = dxguid uuid advapi32 gdi32 user32 wined3d
+
+ C_SRCS = \
+ buffer.c \
+ d3d9_main.c \
++ d3dadapter9.c \
+ device.c \
+ directx.c \
+ query.c \
+diff --git a/dlls/d3d9/d3d9_main.c b/dlls/d3d9/d3d9_main.c
+index 0afdc04..eb5665d 100644
+--- a/dlls/d3d9/d3d9_main.c
++++ b/dlls/d3d9/d3d9_main.c
+@@ -33,12 +33,63 @@ void WINAPI DebugSetMute(void) {
+ /* nothing to do */
+ }
+
++static BOOL try_native(void)
++{
++ HKEY defkey = 0, appkey = 0;
++ DWORD type, data = 0;
++ DWORD size = sizeof(DWORD);
++ DWORD len;
++ char buffer[MAX_PATH];
++
++ /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */
++ if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &defkey ) ) defkey = 0;
++
++ len = GetModuleFileNameA( 0, buffer, MAX_PATH );
++ if (len && len < MAX_PATH)
++ {
++ HKEY tmpkey;
++ /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */
++ if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
++ {
++ char *p, *appname = buffer;
++ if ((p = strrchr( appname, '/' ))) appname = p + 1;
++ if ((p = strrchr( appname, '\\' ))) appname = p + 1;
++ strcat( appname, "\\Direct3D" );
++ TRACE("appname = [%s]\n", appname);
++ if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
++ RegCloseKey( tmpkey );
++ }
++ }
++
++ if (!(appkey && !RegQueryValueExA(appkey, "UseNative", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD))) {
++ if (!(defkey && !RegQueryValueExA(defkey, "UseNative", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD))) {
++ data = 0;
++ }
++ }
++
++ if (appkey) RegCloseKey( appkey );
++ if (defkey) RegCloseKey( defkey );
++
++ if (!data)
++ FIXME("\033[1;33m\nNative Direct3D 9 is disabled."
++ "\nFor more information visit https://wiki.ixit.cz/d3d9\n\033[0m");
++
++ return data ? TRUE : FALSE;
++}
++
+ IDirect3D9 * WINAPI DECLSPEC_HOTPATCH Direct3DCreate9(UINT sdk_version)
+ {
+ struct d3d9 *object;
+
+ TRACE("sdk_version %#x.\n", sdk_version);
+
++ if (try_native()) {
++ IDirect3D9 *native;
++ if (SUCCEEDED(d3dadapter9_new(FALSE, (IDirect3D9Ex **)&native))) {
++ return native;
++ }
++ }
++
+ if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+ return NULL;
+
+@@ -60,6 +111,10 @@ HRESULT WINAPI DECLSPEC_HOTPATCH Direct3DCreate9Ex(UINT sdk_version, IDirect3D9E
+
+ TRACE("sdk_version %#x, d3d9ex %p.\n", sdk_version, d3d9ex);
+
++ if (try_native()) {
++ if (SUCCEEDED(d3dadapter9_new(TRUE, d3d9ex))) { return D3D_OK; }
++ }
++
+ if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
+ return E_OUTOFMEMORY;
+
+@@ -90,6 +145,25 @@ void* WINAPI Direct3DShaderValidatorCreate9(void)
+ return NULL;
+ }
+
++/*******************************************************************
++ * DllMain
++ */
++BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved)
++{
++ switch (reason)
++ {
++ case DLL_PROCESS_ATTACH:
++ d3dadapter9_init(inst);
++ break;
++
++ case DLL_PROCESS_DETACH:
++ d3dadapter9_destroy(inst);
++ break;
++ }
++
++ return TRUE;
++}
++
+ /***********************************************************************
+ * D3DPERF_BeginEvent (D3D9.@)
+ */
+diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h
+index d12805f..cdc1f07 100644
+--- a/dlls/d3d9/d3d9_private.h
++++ b/dlls/d3d9/d3d9_private.h
+@@ -39,6 +39,9 @@
+ #include "d3d9.h"
+ #include "wine/wined3d.h"
+
++extern void d3dadapter9_init(HINSTANCE hinst);
++extern void d3dadapter9_destroy(HINSTANCE hinst);
++
+ extern HRESULT vdecl_convert_fvf(DWORD FVF, D3DVERTEXELEMENT9 **ppVertexElements) DECLSPEC_HIDDEN;
+ D3DFORMAT d3dformat_from_wined3dformat(enum wined3d_format_id format) DECLSPEC_HIDDEN;
+ enum wined3d_format_id wined3dformat_from_d3dformat(D3DFORMAT format) DECLSPEC_HIDDEN;
+@@ -132,6 +135,7 @@ struct d3d9
+
+ BOOL d3d9_init(struct d3d9 *d3d9, BOOL extended) DECLSPEC_HIDDEN;
+ void filter_caps(D3DCAPS9* pCaps) DECLSPEC_HIDDEN;
++HRESULT d3dadapter9_new(boolean ex, IDirect3D9Ex **ppOut);
+
+ struct fvf_declaration
+ {
+diff --git a/dlls/d3d9/d3dadapter9.c b/dlls/d3d9/d3dadapter9.c
+new file mode 100644
+index 0000000..3c75ae0
+--- /dev/null
++++ b/dlls/d3d9/d3dadapter9.c
+@@ -0,0 +1,943 @@
++/*
++ * X11DRV IDirect3D9 interface using ID3DAdapter9
++ *
++ * Copyright 2013 Joakim Sindholt
++ * Christoph Bumiller
++ *
++ * 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"
++
++#include <d3d9.h>
++
++#ifdef SONAME_D3DADAPTER9
++
++#include "wine/d3dadapter.h"
++#include "wine/gdi_driver.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
++
++/* 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;
++
++ struct d3dadapter_funcs *funcs;
++ /* fake window for getting driver funcs */
++ HWND hwnd;
++ HDC hdc;
++
++ /* true if it implements IDirect3D9Ex */
++ boolean ex;
++};
++
++/* 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);
++ }
++
++ if (This->hdc) { ReleaseDC(This->hwnd, This->hdc); }
++ if (This->hwnd) { DestroyWindow(This->hwnd); }
++
++ 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;
++
++ 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;
++ }
++ hr = This->funcs->create_present_group(group->devname, ordinal,
++ hFocusWindow,
++ pPresentationParameters,
++ nparams, &present);
++ }
++
++ 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 = This->funcs->create_adapter9(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
++};
++
++#define D3D9_FAKE_WNDCLASS "FAKED3D9WINDOW"
++
++void
++d3dadapter9_init( HINSTANCE hinst )
++{
++ WNDCLASSA wc;
++
++ wc.style = CS_HREDRAW | CS_VREDRAW;
++ wc.lpfnWndProc = DefWindowProcA;
++ wc.cbClsExtra = 0;
++ wc.cbWndExtra = 0;
++ wc.hInstance = hinst;
++ wc.hIcon = LoadIconA(NULL, (LPCSTR)IDI_WINLOGO);
++ wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
++ wc.hbrBackground = NULL;
++ wc.lpszMenuName = NULL;
++ wc.lpszClassName = D3D9_FAKE_WNDCLASS;
++
++ if (!RegisterClassA(&wc)) {
++ ERR("Unable to register window to retrieve driver info.\n");
++ }
++}
++
++void
++d3dadapter9_destroy( HINSTANCE hinst )
++{
++ UnregisterClassA(D3D9_FAKE_WNDCLASS, hinst);
++}
++
++static int
++load_adapter_funcs( struct d3dadapter9 *This )
++{
++ This->hwnd = CreateWindowA(D3D9_FAKE_WNDCLASS, "D3DAdapter9 fake window",
++ WS_OVERLAPPEDWINDOW, 10, 10, 10, 10,
++ NULL, NULL, NULL, NULL);
++ if (!This->hwnd) {
++ ERR("Unable to create fake window to retrieve driver info.\n");
++ return FALSE;
++ }
++ This->hdc = GetDC(This->hwnd);
++ if (!This->hdc) {
++ ERR("Unable to get fake window DC to retrieve driver info.\n");
++ return FALSE;
++ }
++
++ This->funcs =
++ __wine_get_d3dadapter_driver(This->hdc, WINE_D3DADAPTER_DRIVER_VERSION);
++ if (!This->funcs || !This->funcs->create_adapter9) {
++ WARN("Your display driver doesn't support native D3D9 adapters.\n");
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++HRESULT
++d3dadapter9_new( 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;
++
++ if (!load_adapter_funcs(This)) {
++ 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;
++}
++
++#else
++
++HRESULT
++d3dadapter9_new( boolean ex,
++ IDirect3D9Ex **ppOut )
++{
++ return D3DERR_NOTAVAILABLE;
++}
++
++void
++d3dadapter9_init( HINSTANCE hinst )
++{
++}
++
++void
++d3dadapter9_destroy( HINSTANCE hinst )
++{
++}
++
++#endif /* SONAME_D3DADAPTER9 */
+diff --git a/dlls/gdi32/Makefile.in b/dlls/gdi32/Makefile.in
+index 6cc026c..703968d 100644
+--- a/dlls/gdi32/Makefile.in
++++ b/dlls/gdi32/Makefile.in
+@@ -12,6 +12,7 @@ C_SRCS = \
+ bitmap.c \
+ brush.c \
+ clipping.c \
++ d3dadapter.c \
+ dc.c \
+ dib.c \
+ dibdrv/bitblt.c \
+diff --git a/dlls/gdi32/bitblt.c b/dlls/gdi32/bitblt.c
+index 08ebfd9..d427070 100644
+--- a/dlls/gdi32/bitblt.c
++++ b/dlls/gdi32/bitblt.c
+@@ -559,8 +559,8 @@ BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop
+ /***********************************************************************
+ * BitBlt (GDI32.@)
+ */
+-BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
+- INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
++BOOL WINAPI DECLSPEC_HOTPATCH BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
++ INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
+ {
+ if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
+ else return StretchBlt( hdcDst, xDst, yDst, width, height,
+diff --git a/dlls/gdi32/d3dadapter.c b/dlls/gdi32/d3dadapter.c
+new file mode 100644
+index 0000000..fbf2cd0
+--- /dev/null
++++ b/dlls/gdi32/d3dadapter.c
+@@ -0,0 +1,41 @@
++/*
++ * d3dadapter function forwarding to the display driver
++ *
++ * Copyright (c) 1999 Lionel Ulmer
++ * Copyright (c) 2005 Raphael Junqueira
++ * Copyright (c) 2006 Roderick Colenbrander
++ * Copyright (c) 2013 Joakim Sindholt
++ *
++ * 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 "gdi_private.h"
++
++/***********************************************************************
++ * __wine_get_d3dadapter_driver (GDI32.@)
++ */
++struct d3dadapter_funcs * CDECL __wine_get_d3dadapter_driver( HDC hdc, UINT version )
++{
++ struct d3dadapter_funcs *ret = NULL;
++ DC * dc = get_dc_ptr( hdc );
++
++ if (dc)
++ {
++ PHYSDEV physdev = GET_DC_PHYSDEV( dc, wine_get_d3dadapter_driver );
++ ret = physdev->funcs->wine_get_d3dadapter_driver( physdev, version );
++ release_dc_ptr( dc );
++ }
++ return ret;
++}
+diff --git a/dlls/gdi32/dib.c b/dlls/gdi32/dib.c
+index 708a9a8..2817ede 100644
+--- a/dlls/gdi32/dib.c
++++ b/dlls/gdi32/dib.c
+@@ -59,6 +59,8 @@
+ Search for "Bitmap Structures" in MSDN
+ */
+
++#include "config.h"
++
+ #include <stdarg.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -602,9 +604,10 @@ done:
+ /***********************************************************************
+ * StretchDIBits (GDI32.@)
+ */
+-INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
+- INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, const void *bits,
+- const BITMAPINFO *bmi, UINT coloruse, DWORD rop )
++INT WINAPI DECLSPEC_HOTPATCH StretchDIBits( HDC hdc, INT xDst, INT yDst, INT widthDst, INT heightDst,
++ INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
++ const void *bits, const BITMAPINFO *bmi, UINT coloruse,
++ DWORD rop )
+ {
+ char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
+ BITMAPINFO *info = (BITMAPINFO *)buffer;
+diff --git a/dlls/gdi32/dibdrv/dc.c b/dlls/gdi32/dibdrv/dc.c
+index 7203a8d..70bbb23 100644
+--- a/dlls/gdi32/dibdrv/dc.c
++++ b/dlls/gdi32/dibdrv/dc.c
+@@ -523,6 +523,7 @@ const struct gdi_dc_funcs dib_driver =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ dibdrv_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_DIB_DRV /* priority */
+ };
+
+@@ -1143,5 +1144,6 @@ static const struct gdi_dc_funcs window_driver =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ windrv_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_DIB_DRV + 10 /* priority */
+ };
+diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
+index a6b138c..3c88600 100644
+--- a/dlls/gdi32/driver.c
++++ b/dlls/gdi32/driver.c
+@@ -633,6 +633,11 @@ static struct opengl_funcs *nulldrv_wine_get_wgl_driver( PHYSDEV dev, UINT versi
+ return (void *)-1;
+ }
+
++static struct d3dadapter_funcs *nulldrv_wine_get_d3dadapter_driver( PHYSDEV dev, UINT version )
++{
++ return NULL;
++}
++
+ const struct gdi_dc_funcs null_driver =
+ {
+ nulldrv_AbortDoc, /* pAbortDoc */
+@@ -762,6 +767,7 @@ const struct gdi_dc_funcs null_driver =
+ nulldrv_UnrealizePalette, /* pUnrealizePalette */
+ nulldrv_WidenPath, /* pWidenPath */
+ nulldrv_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ nulldrv_wine_get_d3dadapter_driver, /* wine_get_d3dadapter_driver */
+
+ GDI_PRIORITY_NULL_DRV /* priority */
+ };
+diff --git a/dlls/gdi32/enhmfdrv/init.c b/dlls/gdi32/enhmfdrv/init.c
+index 34b3de6..90982b3 100644
+--- a/dlls/gdi32/enhmfdrv/init.c
++++ b/dlls/gdi32/enhmfdrv/init.c
+@@ -163,6 +163,7 @@ static const struct gdi_dc_funcs EMFDRV_Funcs =
+ NULL, /* pUnrealizePalette */
+ EMFDRV_WidenPath, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
+index de40d9f..3c500a0 100644
+--- a/dlls/gdi32/freetype.c
++++ b/dlls/gdi32/freetype.c
+@@ -364,6 +364,12 @@ typedef struct {
+ GdiFont *font;
+ } CHILD_FONT;
+
++struct font_fileinfo {
++ FILETIME writetime;
++ LARGE_INTEGER size;
++ WCHAR path[1];
++};
++
+ struct tagGdiFont {
+ struct list entry;
+ struct list unused_entry;
+@@ -400,6 +406,7 @@ struct tagGdiFont {
+ const VOID *vert_feature;
+ DWORD cache_num;
+ DWORD instance_id;
++ struct font_fileinfo *fileinfo;
+ };
+
+ typedef struct {
+@@ -4505,6 +4512,7 @@ static void free_font(GdiFont *font)
+ HeapFree(GetProcessHeap(), 0, child);
+ }
+
++ HeapFree(GetProcessHeap(), 0, font->fileinfo);
+ free_font_handle(font->instance_id);
+ if (font->ft_face) pFT_Done_Face(font->ft_face);
+ if (font->mapping) unmap_font_file( font->mapping );
+@@ -5161,6 +5169,29 @@ static const VOID * get_GSUB_vert_feature(const GdiFont *font)
+ return feature;
+ }
+
++static void fill_fileinfo_from_face( GdiFont *font, Face *face )
++{
++ WIN32_FILE_ATTRIBUTE_DATA info;
++ int len;
++
++ if (!face->file)
++ {
++ font->fileinfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font->fileinfo));
++ return;
++ }
++
++ len = strlenW(face->file);
++ font->fileinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
++ if (GetFileAttributesExW(face->file, GetFileExInfoStandard, &info))
++ {
++ font->fileinfo->writetime = info.ftLastWriteTime;
++ font->fileinfo->size.QuadPart = (LONGLONG)info.nFileSizeHigh << 32 | info.nFileSizeLow;
++ strcpyW(font->fileinfo->path, face->file);
++ }
++ else
++ memset(&font->fileinfo, 0, sizeof(*font->fileinfo) + len * sizeof(WCHAR));
++}
++
+ /*************************************************************
+ * freetype_SelectFont
+ */
+@@ -5555,6 +5586,7 @@ found_face:
+ goto done;
+ }
+
++ fill_fileinfo_from_face( ret, face );
+ ret->ntmFlags = face->ntmFlags;
+
+ pick_charmap( ret->ft_face, ret->charset );
+@@ -8238,7 +8270,7 @@ static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
+ return dev->funcs->pGetFontRealizationInfo( dev, ptr );
+ }
+
+- FIXME("(%p, %p): stub!\n", physdev->font, info);
++ TRACE("(%p, %p)\n", physdev->font, info);
+
+ info->flags = 1;
+ if(FT_IS_SCALABLE(physdev->font->ft_face))
+@@ -8256,6 +8288,33 @@ static BOOL freetype_GetFontRealizationInfo( PHYSDEV dev, void *ptr )
+ }
+
+ /*************************************************************************
++ * GetFontFileInfo (GDI32.@)
++ */
++BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed )
++{
++ struct font_handle_entry *entry = handle_entry( instance_id );
++ const GdiFont *font;
++
++ if (!entry)
++ {
++ SetLastError(ERROR_INVALID_PARAMETER);
++ return FALSE;
++ }
++
++ font = entry->obj;
++ *needed = sizeof(*info) + strlenW(font->fileinfo->path) * sizeof(WCHAR);
++ if (*needed > size)
++ {
++ SetLastError(ERROR_INSUFFICIENT_BUFFER);
++ return FALSE;
++ }
++
++ /* path is included too */
++ memcpy(info, font->fileinfo, *needed);
++ return TRUE;
++}
++
++/*************************************************************************
+ * Kerning support for TrueType fonts
+ */
+ #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
+@@ -8639,11 +8698,14 @@ static const struct gdi_dc_funcs freetype_funcs =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_FONT_DRV /* priority */
+ };
+
+ #else /* HAVE_FREETYPE */
+
++struct font_fileinfo;
++
+ /*************************************************************************/
+
+ BOOL WineEngInit(void)
+@@ -8687,4 +8749,13 @@ BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
+ return TRUE;
+ }
+
++/*************************************************************************
++ * GetFontFileInfo (GDI32.@)
++ */
++BOOL WINAPI GetFontFileInfo( DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed)
++{
++ *needed = 0;
++ return FALSE;
++}
++
+ #endif /* HAVE_FREETYPE */
+diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec
+index 8bba686..6329c26 100644
+--- a/dlls/gdi32/gdi32.spec
++++ b/dlls/gdi32/gdi32.spec
+@@ -279,6 +279,7 @@
+ @ stdcall GetEnhMetaFileW(wstr)
+ # @ stub GetFontAssocStatus
+ @ stdcall GetFontData(long long long ptr long)
++@ stdcall GetFontFileInfo(long long ptr long ptr)
+ @ stdcall GetFontLanguageInfo(long)
+ @ stdcall GetFontRealizationInfo(long ptr)
+ @ stub GetFontResourceInfo
+@@ -521,3 +522,6 @@
+
+ # OpenGL
+ @ cdecl __wine_get_wgl_driver(long long)
++
++# Native Direct3D
++@ cdecl __wine_get_d3dadapter_driver(long long)
+diff --git a/dlls/gdi32/mfdrv/init.c b/dlls/gdi32/mfdrv/init.c
+index 50f8ba3..e35d7d8 100644
+--- a/dlls/gdi32/mfdrv/init.c
++++ b/dlls/gdi32/mfdrv/init.c
+@@ -226,6 +226,7 @@ static const struct gdi_dc_funcs MFDRV_Funcs =
+ NULL, /* pUnrealizePalette */
+ MFDRV_WidenPath, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/gdi32/path.c b/dlls/gdi32/path.c
+index e09cd0b..6dc322c 100644
+--- a/dlls/gdi32/path.c
++++ b/dlls/gdi32/path.c
+@@ -2345,5 +2345,6 @@ const struct gdi_dc_funcs path_driver =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_PATH_DRV /* priority */
+ };
+diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
+index dff0eb6..fd9bda3 100644
+--- a/dlls/gdi32/tests/font.c
++++ b/dlls/gdi32/tests/font.c
+@@ -4177,14 +4177,14 @@ static void test_RealizationInfo(void)
+ ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
+ ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
+
+- if (!is_truetype_font_installed("Arial"))
++ if (!is_truetype_font_installed("Tahoma"))
+ {
+ skip("skipping GdiRealizationInfo with truetype font\n");
+ goto end;
+ }
+
+ memset(&lf, 0, sizeof(lf));
+- strcpy(lf.lfFaceName, "Arial");
++ strcpy(lf.lfFaceName, "Tahoma");
+ lf.lfHeight = 20;
+ lf.lfWeight = FW_NORMAL;
+ hfont = CreateFontIndirectA(&lf);
+@@ -4238,12 +4238,19 @@ static void test_RealizationInfo(void)
+ ok(info2[6] == 0xcccccccc, "structure longer than 6 dwords\n");
+
+ /* Test GetFontFileInfo() */
+- if (pGetFontFileInfo) {
++ /* invalid font id */
++ SetLastError(0xdeadbeef);
++ r = pGetFontFileInfo(0xabababab, 0, &file_info, sizeof(file_info), &needed);
++ ok(r == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "ret %d gle %d\n", r, GetLastError());
++
++ needed = 0;
+ r = pGetFontFileInfo(fri->instance_id, 0, &file_info, sizeof(file_info), &needed);
+ ok(r != 0 || GetLastError() == ERROR_NOACCESS, "ret %d gle %d\n", r, GetLastError());
+
+ if (r)
+ {
++ ok(needed > 0 && needed < sizeof(file_info), "got needed size %u\n", needed);
++
+ h = CreateFileW(file_info.path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ ok(h != INVALID_HANDLE_VALUE, "Unable to open file %d\n", GetLastError());
+
+@@ -4256,8 +4263,14 @@ static void test_RealizationInfo(void)
+ ReadFile(h, file, sizeof(file), &read, NULL);
+ CloseHandle(h);
+ have_file = TRUE;
++
++ /* shorter buffer */
++ SetLastError(0xdeadbeef);
++ r = pGetFontFileInfo(fri->instance_id, 0, &file_info, needed - 1, &needed);
++ ok(r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "ret %d gle %d\n", r, GetLastError());
+ }
+
++ if (pGetFontFileData) {
+ /* Get bytes 2 - 16 using GetFontFileData */
+ r = pGetFontFileData(fri->instance_id, 0, 2, data, sizeof(data));
+ ok(r != 0, "ret 0 gle %d\n", GetLastError());
+@@ -5958,6 +5971,7 @@ static void test_stock_fonts(void)
+ {
+ { /* ANSI_FIXED_FONT */
+ { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_ARABIC },
++ { ANSI_CHARSET, FW_NORMAL, 12, 12, 96, "Courier", LANG_HEBREW},
+ { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 96, "Courier" },
+ { DEFAULT_CHARSET, FW_NORMAL, 12, 13, 120, "Courier" },
+ { 0 }
+diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c
+index 6f8e45e..35057f1 100644
+--- a/dlls/hidclass.sys/descriptor.c
++++ b/dlls/hidclass.sys/descriptor.c
+@@ -414,7 +414,7 @@ void parse_io_feature(unsigned int bSize, int itemVal, int bTag, unsigned int *f
+ if ((itemVal & INPUT_ARRAY) == 0)
+ feature->isArray= TRUE;
+ else
+- feature->isArray= TRUE; /* Var */
++ feature->isArray= FALSE; /* Var */
+ if ((itemVal & INPUT_ABS) == 0)
+ feature->IsAbsolute = TRUE;
+ else
+diff --git a/dlls/kernel32/profile.c b/dlls/kernel32/profile.c
+index a9a11b1..aad3ba3 100644
+--- a/dlls/kernel32/profile.c
++++ b/dlls/kernel32/profile.c
+@@ -1402,8 +1402,8 @@ BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
+ /***********************************************************************
+ * WritePrivateProfileStringA (KERNEL32.@)
+ */
+-BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
+- LPCSTR string, LPCSTR filename )
++BOOL WINAPI DECLSPEC_HOTPATCH WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
++ LPCSTR string, LPCSTR filename )
+ {
+ UNICODE_STRING sectionW, entryW, stringW, filenameW;
+ BOOL ret;
+diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c
+index b324160..ed61ab0 100644
+--- a/dlls/mshtml/navigate.c
++++ b/dlls/mshtml/navigate.c
+@@ -1137,7 +1137,7 @@ static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedire
+ return ref;
+ }
+
+-static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
++static nsresult NSAPI nsAsyncVerifyRedirectCallback_OnRedirectVerifyCallback(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
+ {
+ nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
+ nsChannel *old_nschannel;
+@@ -1184,7 +1184,7 @@ static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtb
+ nsAsyncVerifyRedirectCallback_QueryInterface,
+ nsAsyncVerifyRedirectCallback_AddRef,
+ nsAsyncVerifyRedirectCallback_Release,
+- nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
++ nsAsyncVerifyRedirectCallback_OnRedirectVerifyCallback
+ };
+
+ static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
+diff --git a/dlls/mshtml/nsio.c b/dlls/mshtml/nsio.c
+index a661c4d..45ad55f 100644
+--- a/dlls/mshtml/nsio.c
++++ b/dlls/mshtml/nsio.c
+@@ -363,7 +363,7 @@ static http_header_t *find_http_header(struct list *headers, const WCHAR *name,
+ http_header_t *iter;
+
+ LIST_FOR_EACH_ENTRY(iter, headers, http_header_t, entry) {
+- if(!strcmpiW(iter->header, name))
++ if(!strncmpiW(iter->header, name, len) && !iter->header[len])
+ return iter;
+ }
+
+diff --git a/dlls/msvcrt/except_i386.c b/dlls/msvcrt/except_i386.c
+index 6cbb758..1625854 100644
+--- a/dlls/msvcrt/except_i386.c
++++ b/dlls/msvcrt/except_i386.c
+@@ -1127,7 +1127,7 @@ void __stdcall _seh_longjmp_unwind(struct MSVCRT___JUMP_BUFFER *jmp)
+ */
+ void __stdcall _seh_longjmp_unwind4(struct MSVCRT___JUMP_BUFFER *jmp)
+ {
+- msvcrt_local_unwind4( (void *)jmp->Cookie, (MSVCRT_EXCEPTION_FRAME *)jmp->Registration,
++ msvcrt_local_unwind4( (ULONG *)&jmp->Cookie, (MSVCRT_EXCEPTION_FRAME *)jmp->Registration,
+ jmp->TryLevel, (void *)jmp->Ebp );
+ }
+
+diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
+index f589621..4faafe9 100644
+--- a/dlls/ntdll/directory.c
++++ b/dlls/ntdll/directory.c
+@@ -48,7 +48,22 @@
+ #include <sys/attr.h>
+ #endif
+ #ifdef HAVE_SYS_VNODE_H
++/* Work around a conflict with Solaris' system list defined in sys/list.h. */
++#define list SYSLIST
++#define list_next SYSLIST_NEXT
++#define list_prev SYSLIST_PREV
++#define list_head SYSLIST_HEAD
++#define list_tail SYSLIST_TAIL
++#define list_move_tail SYSLIST_MOVE_TAIL
++#define list_remove SYSLIST_REMOVE
+ #include <sys/vnode.h>
++#undef list
++#undef list_next
++#undef list_prev
++#undef list_head
++#undef list_tail
++#undef list_move_tail
++#undef list_remove
+ #endif
+ #ifdef HAVE_SYS_IOCTL_H
+ #include <sys/ioctl.h>
+diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
+index be6b591..8f89ba5 100644
+--- a/dlls/ntdll/file.c
++++ b/dlls/ntdll/file.c
+@@ -61,7 +61,22 @@
+ # include <utime.h>
+ #endif
+ #ifdef HAVE_SYS_VFS_H
++/* Work around a conflict with Solaris' system list defined in sys/list.h. */
++#define list SYSLIST
++#define list_next SYSLIST_NEXT
++#define list_prev SYSLIST_PREV
++#define list_head SYSLIST_HEAD
++#define list_tail SYSLIST_TAIL
++#define list_move_tail SYSLIST_MOVE_TAIL
++#define list_remove SYSLIST_REMOVE
+ # include <sys/vfs.h>
++#undef list
++#undef list_next
++#undef list_prev
++#undef list_head
++#undef list_tail
++#undef list_move_tail
++#undef list_remove
+ #endif
+ #ifdef HAVE_SYS_MOUNT_H
+ # include <sys/mount.h>
+diff --git a/dlls/ntdsapi/ntdsapi.c b/dlls/ntdsapi/ntdsapi.c
+index 2a313ec..ee0c837 100644
+--- a/dlls/ntdsapi/ntdsapi.c
++++ b/dlls/ntdsapi/ntdsapi.c
+@@ -225,7 +225,7 @@ DWORD WINAPI DsClientMakeSpnForTargetServerW(LPCWSTR class, LPCWSTR name, DWORD
+ p = buf + strlenW(class);
+ *p++ = '/';
+ memcpy(p, name, strlenW(name) * sizeof(WCHAR));
+- buf[len] = 0;
++ buf[len - 1] = 0;
+
+ return ERROR_SUCCESS;
+ }
+diff --git a/dlls/openal32/openal.c b/dlls/openal32/openal.c
+index 5a4e1e7..cd49b92 100644
+--- a/dlls/openal32/openal.c
++++ b/dlls/openal32/openal.c
+@@ -99,6 +99,8 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
+ {
+ switch(reason)
+ {
++ case DLL_WINE_PREATTACH:
++ return FALSE; /* prefer native version */
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hinst);
+ #define LOADFUNC(x) x = alcGetProcAddress(NULL, #x)
+diff --git a/dlls/psapi/tests/psapi_main.c b/dlls/psapi/tests/psapi_main.c
+index d7d3a1e..799f0d8 100644
+--- a/dlls/psapi/tests/psapi_main.c
++++ b/dlls/psapi/tests/psapi_main.c
+@@ -147,23 +147,6 @@ static void test_EnumProcessModules(void)
+ ok(hMod == GetModuleHandleA(NULL),
+ "hMod=%p GetModuleHandleA(NULL)=%p\n", hMod, GetModuleHandleA(NULL));
+ ok(cbNeeded % sizeof(hMod) == 0, "not a multiple of sizeof(HMODULE) cbNeeded=%d\n", cbNeeded);
+- /* Windows sometimes has a bunch of extra dlls, presumably brought in by
+- * aclayers.dll.
+- */
+- if (cbNeeded < 4 * sizeof(HMODULE) || cbNeeded > 30 * sizeof(HMODULE))
+- {
+- HMODULE hmods[100];
+- int i;
+- ok(0, "cbNeeded=%d\n", cbNeeded);
+-
+- pEnumProcessModules(hpQV, hmods, sizeof(hmods), &cbNeeded);
+- for (i = 0 ; i < cbNeeded/sizeof(*hmods); i++)
+- {
+- char path[1024];
+- GetModuleFileNameA(hmods[i], path, sizeof(path));
+- trace("i=%d hmod=%p path=[%s]\n", i, hmods[i], path);
+- }
+- }
+ }
+
+ static void test_GetModuleInformation(void)
+@@ -242,7 +225,7 @@ static void test_GetPerformanceInfo(void)
+ ok(check_with_margin(info.CommitPeak, sys_performance_info->PeakCommitment, 32),
+ "expected approximately %ld but got %d\n", info.CommitPeak, sys_performance_info->PeakCommitment);
+
+- ok(check_with_margin(info.PhysicalAvailable, sys_performance_info->AvailablePages, 64),
++ ok(check_with_margin(info.PhysicalAvailable, sys_performance_info->AvailablePages, 128),
+ "expected approximately %ld but got %d\n", info.PhysicalAvailable, sys_performance_info->AvailablePages);
+
+ /* TODO: info.SystemCache not checked yet - to which field(s) does this value correspond to? */
+@@ -296,7 +279,7 @@ static void test_GetPerformanceInfo(void)
+ }
+ HeapFree(GetProcessHeap(), 0, sys_process_info);
+
+- ok(check_with_margin(info.HandleCount, handle_count, 8),
++ ok(check_with_margin(info.HandleCount, handle_count, 24),
+ "expected approximately %d but got %d\n", info.HandleCount, handle_count);
+
+ ok(check_with_margin(info.ProcessCount, process_count, 4),
+@@ -641,30 +624,36 @@ static void test_GetModuleFileNameEx(void)
+ SetLastError(0xdeadbeef);
+ memset( szModExPath, 0xcc, sizeof(szModExPath) );
+ ret = pGetModuleFileNameExA(hpQV, NULL, szModExPath, 4 );
+- ok( ret == 4, "wrong length %u\n", ret );
++ ok( ret == 4 || ret == strlen(szModExPath), "wrong length %u\n", ret );
+ ok( broken(szModExPath[3]) /*w2kpro*/ || strlen(szModExPath) == 3,
+ "szModExPath=\"%s\" ret=%d\n", szModExPath, ret );
+ ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
+
+- SetLastError(0xdeadbeef);
+- ret = pGetModuleFileNameExA(hpQV, NULL, szModExPath, 0 );
+- ok( ret == 0, "wrong length %u\n", ret );
+- ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
++ if (0) /* crashes on Windows 10 */
++ {
++ SetLastError(0xdeadbeef);
++ ret = pGetModuleFileNameExA(hpQV, NULL, szModExPath, 0 );
++ ok( ret == 0, "wrong length %u\n", ret );
++ ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
++ }
+
+ SetLastError(0xdeadbeef);
+ memset( buffer, 0xcc, sizeof(buffer) );
+ ret = pGetModuleFileNameExW(hpQV, NULL, buffer, 4 );
+- ok( ret == 4, "wrong length %u\n", ret );
++ ok( ret == 4 || ret == lstrlenW(buffer), "wrong length %u\n", ret );
+ ok( broken(buffer[3]) /*w2kpro*/ || lstrlenW(buffer) == 3,
+ "buffer=%s ret=%d\n", wine_dbgstr_w(buffer), ret );
+ ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
+
+- SetLastError(0xdeadbeef);
+- buffer[0] = 0xcc;
+- ret = pGetModuleFileNameExW(hpQV, NULL, buffer, 0 );
+- ok( ret == 0, "wrong length %u\n", ret );
+- ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
+- ok( buffer[0] == 0xcc, "buffer modified %s\n", wine_dbgstr_w(buffer) );
++ if (0) /* crashes on Windows 10 */
++ {
++ SetLastError(0xdeadbeef);
++ buffer[0] = 0xcc;
++ ret = pGetModuleFileNameExW(hpQV, NULL, buffer, 0 );
++ ok( ret == 0, "wrong length %u\n", ret );
++ ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
++ ok( buffer[0] == 0xcc, "buffer modified %s\n", wine_dbgstr_w(buffer) );
++ }
+ }
+
+ static void test_GetModuleBaseName(void)
+diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
+index a55a109..ae4a3ab 100644
+--- a/dlls/riched20/editor.c
++++ b/dlls/riched20/editor.c
+@@ -3767,7 +3767,10 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
+
+ if (!wParam)
+ wParam = (WPARAM)GetStockObject(SYSTEM_FONT);
+- GetObjectW((HGDIOBJ)wParam, sizeof(LOGFONTW), &lf);
++
++ if (!GetObjectW((HGDIOBJ)wParam, sizeof(LOGFONTW), &lf))
++ return 0;
++
+ hDC = ITextHost_TxGetDC(editor->texthost);
+ ME_CharFormatFromLogFont(hDC, &lf, &fmt);
+ ITextHost_TxReleaseDC(editor->texthost, hDC);
+diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
+index 6de70ba..af44989 100644
+--- a/dlls/wined3d/glsl_shader.c
++++ b/dlls/wined3d/glsl_shader.c
+@@ -1541,6 +1541,51 @@ static unsigned int vec4_varyings(DWORD shader_major, const struct wined3d_gl_in
+ return ret;
+ }
+
++static BOOL needs_legacy_glsl_syntax(const struct wined3d_gl_info *gl_info)
++{
++ return gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
++}
++
++static void PRINTF_ATTR(4, 5) declare_in_varying(const struct wined3d_gl_info *gl_info,
++ struct wined3d_string_buffer *buffer, BOOL flat, const char *format, ...)
++{
++ va_list args;
++ int ret;
++
++ shader_addline(buffer, "%s%s ", flat ? "flat " : "",
++ needs_legacy_glsl_syntax(gl_info) ? "varying" : "in");
++ for (;;)
++ {
++ va_start(args, format);
++ ret = shader_vaddline(buffer, format, args);
++ va_end(args);
++ if (!ret)
++ return;
++ if (!string_buffer_resize(buffer, ret))
++ return;
++ }
++}
++
++static void PRINTF_ATTR(4, 5) declare_out_varying(const struct wined3d_gl_info *gl_info,
++ struct wined3d_string_buffer *buffer, BOOL flat, const char *format, ...)
++{
++ va_list args;
++ int ret;
++
++ shader_addline(buffer, "%s%s ", flat ? "flat " : "",
++ needs_legacy_glsl_syntax(gl_info) ? "varying" : "out");
++ for (;;)
++ {
++ va_start(args, format);
++ ret = shader_vaddline(buffer, format, args);
++ va_end(args);
++ if (!ret)
++ return;
++ if (!string_buffer_resize(buffer, ret))
++ return;
++ }
++}
++
+ /** Generate the variable & register declarations for the GLSL output target */
+ static void shader_generate_glsl_declarations(const struct wined3d_context *context,
+ struct wined3d_string_buffer *buffer, const struct wined3d_shader *shader,
+@@ -1788,6 +1833,11 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont
+ shader_addline(buffer, "} ffp_point;\n");
+ }
+
++ if (!gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
++ {
++ declare_out_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
++ }
++
+ shader_addline(buffer, "uniform vec4 posFixup;\n");
+ shader_addline(buffer, "void order_ps_input(in vec4[%u]);\n", shader->limits->packed_output);
+ }
+@@ -1805,6 +1855,15 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont
+ shader_addline(buffer, " float end;\n");
+ shader_addline(buffer, " float scale;\n");
+ shader_addline(buffer, "} ffp_fog;\n");
++
++ if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
++ {
++ shader_addline(buffer, "float ffp_varying_fogcoord;\n");
++ }
++ else
++ {
++ declare_in_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
++ }
+ }
+
+ if (version->major >= 3)
+@@ -1812,7 +1871,7 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont
+ UINT in_count = min(vec4_varyings(version->major, gl_info), shader->limits->packed_input);
+
+ if (use_vs(state))
+- shader_addline(buffer, "varying vec4 %s_link[%u];\n", prefix, in_count);
++ declare_in_varying(gl_info, buffer, FALSE, "vec4 %s_link[%u];\n", prefix, in_count);
+ shader_addline(buffer, "vec4 %s_in[%u];\n", prefix, in_count);
+ }
+
+@@ -4864,6 +4923,7 @@ static GLuint generate_param_reorder_function(struct shader_glsl_priv *priv,
+ const char *semantic_name;
+ UINT semantic_idx;
+ char reg_mask[6];
++ BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
+
+ string_buffer_clear(buffer);
+
+@@ -4879,6 +4939,11 @@ static GLuint generate_param_reorder_function(struct shader_glsl_priv *priv,
+
+ if (ps_major < 3)
+ {
++ if (!legacy_context)
++ {
++ declare_out_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
++ }
++
+ shader_addline(buffer, "void order_ps_input(in vec4 vs_out[%u])\n{\n", vs->limits->packed_output);
+
+ for (i = 0; i < vs->output_signature.element_count; ++i)
+@@ -4928,7 +4993,8 @@ static GLuint generate_param_reorder_function(struct shader_glsl_priv *priv,
+ }
+ else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_FOG))
+ {
+- shader_addline(buffer, "gl_FogFragCoord = clamp(vs_out[%u].%c, 0.0, 1.0);\n",
++ shader_addline(buffer, "%s = clamp(vs_out[%u].%c, 0.0, 1.0);\n",
++ legacy_context ? "gl_FogFragCoord" : "ffp_varying_fogcoord",
+ output->register_idx, reg_mask[1]);
+ }
+ }
+@@ -4937,8 +5003,8 @@ static GLuint generate_param_reorder_function(struct shader_glsl_priv *priv,
+ else
+ {
+ UINT in_count = min(vec4_varyings(ps_major, gl_info), ps->limits->packed_input);
+- /* This one is tricky: a 3.0 pixel shader reads from a 3.0 vertex shader */
+- shader_addline(buffer, "varying vec4 ps_link[%u];\n", in_count);
++
++ declare_out_varying(gl_info, buffer, FALSE, "vec4 ps_link[%u];\n", in_count);
+ shader_addline(buffer, "void order_ps_input(in vec4 vs_out[%u])\n{\n", vs->limits->packed_output);
+
+ /* First, sort out position and point size. Those are not passed to the pixel shader */
+@@ -4997,16 +5063,16 @@ static void shader_glsl_generate_fog_code(struct wined3d_string_buffer *buffer,
+ return;
+
+ case WINED3D_FFP_PS_FOG_LINEAR:
+- shader_addline(buffer, "float fog = (ffp_fog.end - gl_FogFragCoord) * ffp_fog.scale;\n");
++ shader_addline(buffer, "float fog = (ffp_fog.end - ffp_varying_fogcoord) * ffp_fog.scale;\n");
+ break;
+
+ case WINED3D_FFP_PS_FOG_EXP:
+- shader_addline(buffer, "float fog = exp(-ffp_fog.density * gl_FogFragCoord);\n");
++ shader_addline(buffer, "float fog = exp(-ffp_fog.density * ffp_varying_fogcoord);\n");
+ break;
+
+ case WINED3D_FFP_PS_FOG_EXP2:
+ shader_addline(buffer, "float fog = exp(-ffp_fog.density * ffp_fog.density"
+- " * gl_FogFragCoord * gl_FogFragCoord);\n");
++ " * ffp_varying_fogcoord * ffp_varying_fogcoord);\n");
+ break;
+
+ default:
+@@ -5028,6 +5094,7 @@ static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context
+ const struct wined3d_gl_info *gl_info = context->gl_info;
+ const DWORD *function = shader->function;
+ struct shader_glsl_ctx_priv priv_ctx;
++ BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
+
+ /* Create the hw GLSL shader object and assign it as the shader->prgId */
+ GLuint shader_id = GL_EXTCALL(glCreateShader(GL_FRAGMENT_SHADER));
+@@ -5055,6 +5122,12 @@ static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context
+ /* Base Declarations */
+ shader_generate_glsl_declarations(context, buffer, shader, reg_maps, &priv_ctx);
+
++ if (reg_maps->shader_version.major < 3 || args->vp_mode != vertexshader)
++ {
++ if (legacy_context)
++ shader_addline(buffer, "ffp_varying_fogcoord = gl_FogFragCoord;\n");
++ }
++
+ /* Pack 3.0 inputs */
+ if (reg_maps->shader_version.major >= 3)
+ shader_glsl_input_pack(shader, buffer, &shader->input_signature, reg_maps, args);
+@@ -5094,6 +5167,7 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context
+ const struct wined3d_gl_info *gl_info = context->gl_info;
+ const DWORD *function = shader->function;
+ struct shader_glsl_ctx_priv priv_ctx;
++ BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
+
+ /* Create the hw GLSL shader program and assign it as the shader->prgId */
+ GLuint shader_id = GL_EXTCALL(glCreateShader(GL_VERTEX_SHADER));
+@@ -5128,9 +5202,11 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context
+ * the shader, it is set to 0.0(fully fogged, since start = 1.0, end = 0.0)
+ */
+ if (args->fog_src == VS_FOG_Z)
+- shader_addline(buffer, "gl_FogFragCoord = gl_Position.z;\n");
++ shader_addline(buffer, "%s = gl_Position.z;\n",
++ legacy_context ? "gl_FogFragCoord" : "ffp_varying_fogcoord");
+ else if (!reg_maps->fog)
+- shader_addline(buffer, "gl_FogFragCoord = 0.0;\n");
++ shader_addline(buffer, "%s = 0.0;\n",
++ legacy_context ? "gl_FogFragCoord" : "ffp_varying_fogcoord");
+
+ /* We always store the clipplanes without y inversion */
+ if (args->clip_enabled)
+@@ -5592,6 +5668,8 @@ static GLuint shader_glsl_generate_ffp_vertex_shader(struct wined3d_string_buffe
+ };
+ GLuint shader_obj;
+ unsigned int i;
++ BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
++ BOOL output_legacy_fogcoord = legacy_context;
+
+ string_buffer_clear(buffer);
+
+@@ -5646,6 +5724,15 @@ static GLuint shader_glsl_generate_ffp_vertex_shader(struct wined3d_string_buffe
+ shader_addline(buffer, "} ffp_point;\n");
+ }
+
++ if (legacy_context)
++ {
++ shader_addline(buffer, "float ffp_varying_fogcoord;\n");
++ }
++ else
++ {
++ declare_out_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
++ }
++
+ shader_addline(buffer, "\nvoid main()\n{\n");
+ shader_addline(buffer, "float m;\n");
+ shader_addline(buffer, "vec3 r;\n");
+@@ -5746,30 +5833,33 @@ static GLuint shader_glsl_generate_ffp_vertex_shader(struct wined3d_string_buffe
+ switch (settings->fog_mode)
+ {
+ case WINED3D_FFP_VS_FOG_OFF:
++ output_legacy_fogcoord = FALSE;
+ break;
+
+ case WINED3D_FFP_VS_FOG_FOGCOORD:
+- shader_addline(buffer, "gl_FogFragCoord = ffp_attrib_specular.w * 255.0;\n");
++ shader_addline(buffer, "ffp_varying_fogcoord = ffp_attrib_specular.w * 255.0;\n");
+ break;
+
+ case WINED3D_FFP_VS_FOG_RANGE:
+- shader_addline(buffer, "gl_FogFragCoord = length(ec_pos.xyz);\n");
++ shader_addline(buffer, "ffp_varying_fogcoord = length(ec_pos.xyz);\n");
+ break;
+
+ case WINED3D_FFP_VS_FOG_DEPTH:
+ if (settings->ortho_fog)
+ /* Need to undo the [0.0 - 1.0] -> [-1.0 - 1.0] transformation from D3D to GL coordinates. */
+- shader_addline(buffer, "gl_FogFragCoord = gl_Position.z * 0.5 + 0.5;\n");
++ shader_addline(buffer, "ffp_varying_fogcoord = gl_Position.z * 0.5 + 0.5;\n");
+ else if (settings->transformed)
+- shader_addline(buffer, "gl_FogFragCoord = ec_pos.z;\n");
++ shader_addline(buffer, "ffp_varying_fogcoord = ec_pos.z;\n");
+ else
+- shader_addline(buffer, "gl_FogFragCoord = abs(ec_pos.z);\n");
++ shader_addline(buffer, "ffp_varying_fogcoord = abs(ec_pos.z);\n");
+ break;
+
+ default:
+ ERR("Unhandled fog mode %#x.\n", settings->fog_mode);
+ break;
+ }
++ if (output_legacy_fogcoord)
++ shader_addline(buffer, "gl_FogFragCoord = ffp_varying_fogcoord;\n");
+
+ if (settings->point_size)
+ {
+@@ -6048,6 +6138,7 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *
+ DWORD arg0, arg1, arg2;
+ unsigned int stage;
+ struct wined3d_string_buffer *tex_reg_name = string_buffer_get(&priv->string_buffers);
++ BOOL legacy_context = gl_info->supported[WINED3D_GL_LEGACY_CONTEXT];
+
+ string_buffer_clear(buffer);
+
+@@ -6187,8 +6278,20 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *
+ shader_addline(buffer, " float scale;\n");
+ shader_addline(buffer, "} ffp_fog;\n");
+
++ if (legacy_context)
++ {
++ shader_addline(buffer, "float ffp_varying_fogcoord;\n");
++ }
++ else
++ {
++ declare_in_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
++ }
++
+ shader_addline(buffer, "void main()\n{\n");
+
++ if (legacy_context && settings->fog != WINED3D_FFP_PS_FOG_OFF)
++ shader_addline(buffer, "ffp_varying_fogcoord = gl_FogFragCoord;\n");
++
+ if (lowest_disabled_stage < 7 && settings->emul_clipplanes)
+ shader_addline(buffer, "if (any(lessThan(gl_TexCoord[7], vec4(0.0)))) discard;\n");
+
+diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c
+index 9f18ac4..669a7ba 100644
+--- a/dlls/winemac.drv/gdi.c
++++ b/dlls/winemac.drv/gdi.c
+@@ -538,6 +538,7 @@ static const struct gdi_dc_funcs macdrv_funcs =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ macdrv_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/wineps.drv/init.c b/dlls/wineps.drv/init.c
+index 2cdb071..6e2cf0f 100644
+--- a/dlls/wineps.drv/init.c
++++ b/dlls/wineps.drv/init.c
+@@ -950,6 +950,7 @@ static const struct gdi_dc_funcs psdrv_funcs =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in
+index 463eefd..65d32ed 100644
+--- a/dlls/winex11.drv/Makefile.in
++++ b/dlls/winex11.drv/Makefile.in
+@@ -2,13 +2,15 @@ MODULE = winex11.drv
+ IMPORTS = uuid user32 gdi32 advapi32
+ DELAYIMPORTS = comctl32 ole32 shell32 imm32
+ EXTRAINCL = $(X_CFLAGS)
+-EXTRALIBS = $(X_LIBS) $(X_EXTRA_LIBS)
++EXTRALIBS = $(X_LIBS) $(X_EXTRA_LIBS) $(D3DADAPTER9_LIBS)
+
+ C_SRCS = \
+ bitblt.c \
+ brush.c \
+ clipboard.c \
++ d3dadapter.c \
+ desktop.c \
++ dri3.c \
+ event.c \
+ graphics.c \
+ ime.c \
+diff --git a/dlls/winex11.drv/d3dadapter.c b/dlls/winex11.drv/d3dadapter.c
+new file mode 100644
+index 0000000..2b6cfa4
+--- /dev/null
++++ b/dlls/winex11.drv/d3dadapter.c
+@@ -0,0 +1,1189 @@
++/*
++ * X11DRV ID3DAdapter9 support functions
++ *
++ * Copyright 2013 Joakim Sindholt
++ * Christoph Bumiller
++ *
++ * 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);
++
++#if defined(SONAME_LIBXEXT) && \
++ defined(SONAME_LIBXFIXES) && \
++ defined(SONAME_D3DADAPTER9)
++
++#include "wine/d3dadapter.h"
++#include "wine/library.h"
++#include "wine/unicode.h"
++
++#include "x11drv.h"
++
++#include <d3dadapter/drm.h>
++
++#include "xfixes.h"
++#include "dri3.h"
++
++#include <libdrm/drm.h>
++#include <sys/ioctl.h>
++#include <errno.h>
++#include <fcntl.h>
++
++#ifndef D3DPRESENT_DONOTWAIT
++#define D3DPRESENT_DONOTWAIT 0x00000001
++#endif
++
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR 1
++#ifdef ID3DPresent_GetWindowOccluded
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 1
++#else
++#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 0
++#endif
++
++static const struct D3DAdapter9DRM *d3d9_drm = NULL;
++#ifdef D3DADAPTER9_DRI2
++static int is_dri2_fallback = 0;
++#endif
++
++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 occluded;
++};
++
++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(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(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
++ ChangeDisplaySettingsExW(This->devname, &(This->initial_mode), 0, CDS_FULLSCREEN, NULL);
++ PRESENTDestroy(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,
++ BOOL first_time);
++
++static HRESULT WINAPI
++DRI3Present_SetPresentParameters( struct DRI3Present *This,
++ D3DPRESENT_PARAMETERS *pPresentationParameters,
++ D3DDISPLAYMODEEX *pFullscreenDisplayMode )
++{
++ if (pFullscreenDisplayMode)
++ FIXME("Ignoring pFullscreenDisplayMode\n");
++#ifdef ID3DPresent_GetWindowOccluded
++ dri3_present_register_window_hook(This);
++#endif
++ return DRI3Present_ChangePresentParameters(This, pPresentationParameters, FALSE);
++}
++
++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(gdi_display, DefaultScreen(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(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(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(hWndOverride);
++ } else if (This->params.hDeviceWindow) {
++ d3d = get_d3d_drawable(This->params.hDeviceWindow);
++ } else {
++ d3d = get_d3d_drawable(This->focus_wnd);
++ }
++ if (!d3d) { return D3DERR_DRIVERINTERNALERROR; }
++
++ 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(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;
++}
++
++#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;
++ 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;
++ switch (wndprocparams.message) {
++ case WM_ACTIVATE:
++ if(wndprocparams.wParam == WA_INACTIVE) {
++ if (hook->present && !hook->present->params.Windowed) {
++ ShowWindow(hook->present->params.hDeviceWindow, SW_MINIMIZE);
++ ChangeDisplaySettingsExW(hook->present->devname, &(hook->present->initial_mode), 0, 0, NULL);
++ hook->present->occluded = TRUE;
++ }
++ } else {
++ if (hook->present && !hook->present->params.Windowed && hook->present->occluded) {
++ ShowWindow(hook->present->params.hDeviceWindow, SW_RESTORE);
++ hook->present->occluded = FALSE;
++ }
++ }
++ 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 D3D_OK;
++ }
++ /* 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 )
++{
++ 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,
++ BOOL first_time)
++{
++ HWND draw_window;
++ RECT rect;
++ LONG hr;
++
++ (void) first_time; /* will be used to manage screen res if windowed mode change */
++ /* TODO: don't do anything if nothing changed */
++ /* sanitize presentation parameters */
++ draw_window = params->hDeviceWindow ? params->hDeviceWindow : This->focus_wnd;
++
++ 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 (!params->Windowed) {
++ /* TODO Store initial config and restore it when leaving fullscreen, or when leaving wine*/
++ LONG style, exstyle;
++ DEVMODEW newMode;
++
++ ZeroMemory(&newMode, sizeof(DEVMODEW));
++ newMode.dmPelsWidth = params->BackBufferWidth;
++ newMode.dmPelsHeight = params->BackBufferHeight;
++ newMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
++ newMode.dmSize = sizeof(DEVMODEW);
++ hr = ChangeDisplaySettingsExW(This->devname, &newMode, 0, CDS_FULLSCREEN, NULL);
++ if (hr != DISP_CHANGE_SUCCESSFUL) {
++ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++ return D3DERR_INVALIDCALL;
++ }
++ style = fullscreen_style(0);
++ exstyle = fullscreen_exstyle(0);
++
++ SetWindowLongW(draw_window, GWL_STYLE, style);
++ SetWindowLongW(draw_window, GWL_EXSTYLE, exstyle);
++ hr = SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth, params->BackBufferHeight,
++ SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
++ if (!hr) {
++ ERR("SetWindowLongW failed with 0x%08X\n", GetLastError());
++ return D3DERR_INVALIDCALL;
++ }
++ } else if (!first_time && !This->params.Windowed) {
++ hr = ChangeDisplaySettingsExW(This->devname, &(This->initial_mode), 0, CDS_FULLSCREEN, NULL);
++ if (hr != DISP_CHANGE_SUCCESSFUL) {
++ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr);
++ return D3DERR_INVALIDCALL;
++ }
++ }
++ SetForegroundWindow(draw_window);
++
++ This->params = *params;
++ return D3D_OK;
++}
++
++static HRESULT
++DRI3Present_new( Display *dpy,
++ const WCHAR *devname,
++ D3DPRESENT_PARAMETERS *params,
++ HWND focus_wnd,
++ struct DRI3Present **out )
++{
++ struct DRI3Present *This;
++ HRESULT hr;
++
++ 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->vtable = &DRI3Present_vtable;
++ This->refs = 1;
++ This->focus_wnd = focus_wnd;
++
++ 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);
++
++ hr = DRI3Present_ChangePresentParameters(This, params, TRUE);
++ if (hr != D3D_OK)
++ return hr;
++
++ PRESENTInit(dpy, &(This->present_priv));
++#ifdef D3DADAPTER9_DRI2
++ if (is_dri2_fallback)
++ DRI2FallbackInit(dpy, &(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;
++};
++
++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) {
++ 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(gdi_display, This->present_backends[0]->devname,
++ pPresentationParameters, 0, (struct DRI3Present **)ppPresent);
++ 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
++};
++
++static HRESULT
++dri3_create_present_group( const WCHAR *device_name,
++ UINT adapter,
++ HWND focus_wnd,
++ D3DPRESENT_PARAMETERS *params,
++ unsigned nparams,
++ ID3DPresentGroup **group )
++{
++ 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->vtable = &DRI3PresentGroup_vtable;
++ This->refs = 1;
++ 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) {
++ /* 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]);
++ if (FAILED(hr)) {
++ DRI3PresentGroup_Release(This);
++ return hr;
++ }
++ }
++
++ *group = (ID3DPresentGroup *)This;
++ TRACE("Returning %p\n", *group);
++
++ return D3D_OK;
++}
++
++static HRESULT
++dri3_create_adapter9( 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;
++}
++
++static BOOL
++has_d3dadapter( void )
++{
++ static const void * WINAPI (*pD3DAdapter9GetProc)(const char *);
++ static void *handle = NULL;
++ static int done = 0;
++
++ int xfmaj, xfmin;
++ char errbuf[256];
++
++ /* like in opengl.c (single threaded assumption OK?) */
++ if (done) { return handle != NULL; }
++ done = 1;
++
++ /* */
++ if (!usexfixes) {
++ ERR("%s needs Xfixes.\n", SONAME_D3DADAPTER9);
++ return FALSE;
++ }
++
++ 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
++ }
++
++ /* query XFixes */
++ if (!pXFixesQueryVersion(gdi_display, &xfmaj, &xfmin)) {
++ ERR("Unable to query XFixes extension.\n");
++ return D3DERR_DRIVERINTERNALERROR;
++ }
++ TRACE("Got XFixes version %u.%u\n", xfmaj, xfmin);
++ 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;
++}
++
++static struct d3dadapter_funcs dri3_driver = {
++ dri3_create_present_group, /* create_present_group */
++ dri3_create_adapter9, /* create_adapter9 */
++};
++
++struct d3dadapter_funcs *
++get_d3d_dri3_driver(UINT version)
++{
++ if (version != WINE_D3DADAPTER_DRIVER_VERSION) {
++ ERR("Version mismatch. d3d* wants %u but winex11 has "
++ "version %u\n", version, WINE_D3DADAPTER_DRIVER_VERSION);
++ return NULL;
++ }
++ if (has_d3dadapter()) { return &dri3_driver; }
++ return NULL;
++}
++
++#else /* defined(SONAME_LIBXEXT) && \
++ defined(SONAME_LIBXFIXES) && \
++ defined(SONAME_D3DADAPTER9) */
++
++struct d3dadapter_funcs;
++
++void
++destroy_d3dadapter_drawable(HWND hwnd)
++{
++}
++
++static BOOL
++has_d3dadapter( void )
++{
++ FIXME("\033[0;31m\nWine source code has been compiled without native Direct3D 9 support."
++ "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n");
++ return FALSE;
++}
++
++struct d3dadapter_funcs *
++get_d3d_dri3_driver(UINT version)
++{
++ return NULL;
++}
++
++#endif /* defined(SONAME_LIBXEXT) && \
++ defined(SONAME_LIBXFIXES) && \
++ defined(SONAME_D3DADAPTER9) */
+diff --git a/dlls/winex11.drv/dri3.c b/dlls/winex11.drv/dri3.c
+new file mode 100644
+index 0000000..32f4e20
+--- /dev/null
++++ b/dlls/winex11.drv/dri3.c
+@@ -0,0 +1,1339 @@
++/*
++ * 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
++ */
++
++
++#include "config.h"
++#include "wine/debug.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
++
++#if defined(SONAME_LIBXEXT) && defined(SONAME_LIBXFIXES)
++
++#include "x11drv.h"
++#include "wine/d3dadapter.h"
++
++
++#include <stdlib.h>
++#include <fcntl.h>
++
++#include <X11/Xlib.h>
++#include <X11/extensions/Xfixes.h>
++#include <X11/Xlib-xcb.h>
++
++#include "xfixes.h"
++#include "dri3.h"
++#include <pthread.h>
++#include "winbase.h" /* for Sleep */
++
++#ifdef D3DADAPTER9_DRI2
++#include <unistd.h>
++#include <sys/ioctl.h>
++#include <stdio.h>
++#include <string.h>
++#include "x11drv.h"
++#include <X11/Xlibint.h>
++#include <X11/extensions/dri2tokens.h>
++#include <X11/extensions/dri2proto.h>
++#include <X11/extensions/extutil.h>
++#define GL_GLEXT_PROTOTYPES 1
++#define EGL_EGLEXT_PROTOTYPES 1
++#define GL_GLEXT_LEGACY 1
++#include <GL/gl.h>
++/* workaround gl header bug */
++#define glBlendColor glBlendColorLEV
++#define glBlendEquation glBlendEquationLEV
++#include <GL/glext.h>
++#include <EGL/egl.h>
++#include <EGL/eglext.h>
++#include <libdrm/drm_fourcc.h>
++#include <libdrm/drm.h>
++/*GLAPI void GLAPIENTRY glFlush( void );
++
++GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers);
++GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer);
++GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
++GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
++GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
++GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
++GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures);
++EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);*/
++
++typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
++typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
++typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
++
++#endif
++
++BOOL
++DRI3CheckExtension(Display *dpy, int major, int minor)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ xcb_dri3_query_version_cookie_t dri3_cookie;
++ xcb_dri3_query_version_reply_t *dri3_reply;
++ xcb_generic_error_t *error;
++ const xcb_query_extension_reply_t *extension;
++ int fd;
++
++ xcb_prefetch_extension_data(xcb_connection, &xcb_dri3_id);
++
++ extension = xcb_get_extension_data(xcb_connection, &xcb_dri3_id);
++ if (!(extension && extension->present)) {
++ ERR("DRI3 extension is not present\n");
++ return FALSE;
++ }
++
++ dri3_cookie = xcb_dri3_query_version(xcb_connection, major, minor);
++
++ dri3_reply = xcb_dri3_query_version_reply(xcb_connection, dri3_cookie, &error);
++ if (!dri3_reply) {
++ free(error);
++ ERR("Issue getting requested version of DRI3: %d,%d\n", major, minor);
++ return FALSE;
++ }
++
++ if (!DRI3Open(dpy, DefaultScreen(dpy), &fd)) {
++ ERR("DRI3 advertised, but not working\n");
++ return FALSE;
++ }
++ close(fd);
++
++ TRACE("DRI3 version %d,%d found. %d %d requested\n", major, minor, (int)dri3_reply->major_version, (int)dri3_reply->minor_version);
++ free(dri3_reply);
++
++ return TRUE;
++}
++
++#ifdef D3DADAPTER9_DRI2
++
++struct DRI2priv {
++ Display *dpy;
++ EGLDisplay display;
++ EGLContext context;
++ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func;
++ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func;
++ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func;
++};
++
++/* TODO: We don't free memory properly. When exiting, eglTerminate doesn't work well(crash), and things are freed automatically. Rely on it */
++
++BOOL
++DRI2FallbackInit(Display *dpy, struct DRI2priv **priv)
++{
++ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func;
++ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func;
++ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT_func;
++ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func;
++ EGLDisplay display;
++ EGLint major, minor;
++ EGLConfig config;
++ EGLContext context;
++ EGLint i;
++ EGLBoolean b;
++ EGLenum current_api = 0;
++ const char *extensions;
++ EGLint config_attribs[] = {
++ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
++ EGL_NONE
++ };
++ EGLint context_compatibility_attribs[] = {
++ EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR,
++ EGL_NONE
++ };
++
++ current_api = eglQueryAPI();
++ eglGetPlatformDisplayEXT_func = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT");
++ if (!eglGetPlatformDisplayEXT_func)
++ return FALSE;
++ display = eglGetPlatformDisplayEXT_func(EGL_PLATFORM_X11_EXT, dpy, NULL);
++ if (!display)
++ return FALSE;
++ if (eglInitialize(display, &major, &minor) != EGL_TRUE)
++ goto clean_egl_display;
++
++ extensions = eglQueryString(display, EGL_CLIENT_APIS);
++ if (!extensions || !strstr(extensions, "OpenGL"))
++ goto clean_egl_display;
++
++ extensions = eglQueryString(display, EGL_EXTENSIONS);
++ if (!extensions || !strstr(extensions, "EGL_EXT_image_dma_buf_import") ||
++ !strstr(extensions, "EGL_KHR_create_context") ||
++ !strstr(extensions, "EGL_KHR_surfaceless_context") ||
++ !strstr(extensions, "EGL_KHR_image_base"))
++ goto clean_egl_display;
++
++ if (!eglChooseConfig(display, config_attribs, &config, 1, &i))
++ goto clean_egl_display;
++
++ b = eglBindAPI(EGL_OPENGL_API);
++ if (b == EGL_FALSE)
++ goto clean_egl_display;
++ context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_compatibility_attribs);
++ if (context == EGL_NO_CONTEXT)
++ goto clean_egl_display;
++
++ glEGLImageTargetTexture2DOES_func = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES");
++ eglCreateImageKHR_func = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
++ eglDestroyImageKHR_func = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
++ if (!eglCreateImageKHR_func || !glEGLImageTargetTexture2DOES_func || !eglDestroyImageKHR_func) {
++ ERR("eglGetProcAddress failed !");
++ goto clean_egl_display;
++ }
++
++ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++
++ *priv = calloc(1, sizeof(struct DRI2priv));
++ if (!*priv)
++ goto clean_egl;
++ (*priv)->dpy = dpy;
++ (*priv)->display = display;
++ (*priv)->context = context;
++ (*priv)->glEGLImageTargetTexture2DOES_func = glEGLImageTargetTexture2DOES_func;
++ (*priv)->eglCreateImageKHR_func = eglCreateImageKHR_func;
++ (*priv)->eglDestroyImageKHR_func = eglDestroyImageKHR_func;
++ eglBindAPI(current_api);
++ return TRUE;
++
++clean_egl:
++clean_egl_display:
++ eglTerminate(display);
++ eglBindAPI(current_api);
++ return FALSE;
++}
++
++/* hypothesis: at this step all textures, etc are destroyed */
++void
++DRI2FallbackDestroy(struct DRI2priv *priv)
++{
++ EGLenum current_api;
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++ eglMakeCurrent(priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglDestroyContext(priv->display, priv->context);
++ eglTerminate(priv->display);
++ eglBindAPI(current_api);
++ free(priv);
++}
++
++BOOL
++DRI2FallbackCheckSupport(Display *dpy)
++{
++ struct DRI2priv *priv;
++ int fd;
++ if (!DRI2FallbackInit(dpy, &priv))
++ return FALSE;
++ DRI2FallbackDestroy(priv);
++ if (!DRI2FallbackOpen(dpy, DefaultScreen(dpy), &fd))
++ return FALSE;
++ close(fd);
++ return TRUE;
++}
++
++#endif
++
++BOOL
++PRESENTCheckExtension(Display *dpy, int major, int minor)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ xcb_present_query_version_cookie_t present_cookie;
++ xcb_present_query_version_reply_t *present_reply;
++ xcb_generic_error_t *error;
++ const xcb_query_extension_reply_t *extension;
++
++ xcb_prefetch_extension_data(xcb_connection, &xcb_present_id);
++
++ extension = xcb_get_extension_data(xcb_connection, &xcb_present_id);
++ if (!(extension && extension->present)) {
++ ERR("PRESENT extension is not present\n");
++ return FALSE;
++ }
++
++ present_cookie = xcb_present_query_version(xcb_connection, major, minor);
++
++ present_reply = xcb_present_query_version_reply(xcb_connection, present_cookie, &error);
++ if (!present_reply) {
++ free(error);
++ ERR("Issue getting requested version of PRESENT: %d,%d\n", major, minor);
++ return FALSE;
++ }
++
++ TRACE("PRESENT version %d,%d found. %d %d requested\n", major, minor, (int)present_reply->major_version, (int)present_reply->minor_version);
++ free(present_reply);
++
++ return TRUE;
++}
++
++BOOL
++DRI3Open(Display *dpy, int screen, int *device_fd)
++{
++ xcb_dri3_open_cookie_t cookie;
++ xcb_dri3_open_reply_t *reply;
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ int fd;
++ Window root = RootWindow(dpy, screen);
++
++ cookie = xcb_dri3_open(xcb_connection, root, 0);
++
++ reply = xcb_dri3_open_reply(xcb_connection, cookie, NULL);
++ if (!reply)
++ return FALSE;
++
++ if (reply->nfd != 1) {
++ free(reply);
++ return FALSE;
++ }
++
++ fd = xcb_dri3_open_reply_fds(xcb_connection, reply)[0];
++ fcntl(fd, F_SETFD, FD_CLOEXEC);
++
++ *device_fd = fd;
++ free(reply);
++
++ return TRUE;
++}
++
++#ifdef D3DADAPTER9_DRI2
++
++static XExtensionInfo _dri2_info_data;
++static XExtensionInfo *dri2_info = &_dri2_info_data;
++static char dri2_name[] = DRI2_NAME;
++
++#define DRI2CheckExtension(dpy, i, val) \
++ XextCheckExtension(dpy, i, dri2_name, val)
++
++
++static int
++close_display(Display *dpy,
++ XExtCodes *codes);
++static Bool
++wire_to_event(Display *dpy,
++ XEvent *re,
++ xEvent *event);
++static Status
++event_to_wire(Display *dpy,
++ XEvent *re,
++ xEvent *event);
++static int
++error( Display *dpy,
++ xError *err,
++ XExtCodes *codes,
++ int *ret_code );
++static XExtensionHooks dri2_hooks = {
++ NULL, /* create_gc */
++ NULL, /* copy_gc */
++ NULL, /* flush_gc */
++ NULL, /* free_gc */
++ NULL, /* create_font */
++ NULL, /* free_font */
++ close_display, /* close_display */
++ wire_to_event, /* wire_to_event */
++ event_to_wire, /* event_to_wire */
++ error, /* error */
++ NULL, /* error_string */
++};
++static XEXT_GENERATE_CLOSE_DISPLAY(close_display, dri2_info);
++static XEXT_GENERATE_FIND_DISPLAY(find_display, dri2_info,
++ dri2_name, &dri2_hooks, 0, NULL);
++static Bool
++wire_to_event(Display *dpy,
++ XEvent *re,
++ xEvent *event)
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ DRI2CheckExtension(dpy, info, False);
++ TRACE("dri2 wire_to_event\n");
++ return False;
++}
++static Status
++event_to_wire(Display *dpy,
++ XEvent *re,
++ xEvent *event)
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ DRI2CheckExtension(dpy, info, False);
++ TRACE("dri2 event_to_wire\n");
++ return False;
++}
++static int
++error(Display *dpy,
++ xError *err,
++ XExtCodes *codes,
++ int *ret_code)
++{
++ TRACE("dri2 error\n");
++ return False;
++}
++
++#define XALIGN(x) (((x) + 3) & (~3))
++
++static BOOL
++DRI2Connect(Display *dpy,
++ XID window,
++ unsigned driver_type,
++ char **device )
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ xDRI2ConnectReply rep;
++ xDRI2ConnectReq *req;
++ int dev_len, driv_len;
++ char *driver;
++
++ DRI2CheckExtension(dpy, info, False);
++
++ LockDisplay(dpy);
++ GetReq(DRI2Connect, req);
++ req->reqType = info->codes->major_opcode;
++ req->dri2ReqType = X_DRI2Connect;
++ req->window = window;
++ req->driverType = driver_type;
++ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++
++ /* check string lengths */
++ dev_len = rep.deviceNameLength;
++ driv_len = rep.driverNameLength;
++ if (dev_len == 0 || driv_len == 0) {
++ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len));
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++
++ /* read out driver */
++ driver = HeapAlloc(GetProcessHeap(), 0, driv_len + 1);
++ if (!driver) {
++ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len));
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++ _XReadPad(dpy, driver, driv_len);
++ HeapFree(GetProcessHeap(), 0, driver); /* we don't need the driver */
++
++ /* read out device */
++ *device = HeapAlloc(GetProcessHeap(), 0, dev_len + 1);
++ if (!*device) {
++ _XEatData(dpy, XALIGN(dev_len));
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++ _XReadPad(dpy, *device, dev_len);
++ (*device)[dev_len] = '\0';
++
++ UnlockDisplay(dpy);
++ SyncHandle();
++
++ return True;
++}
++
++static Bool
++DRI2Authenticate(Display *dpy,
++ XID window,
++ uint32_t token)
++{
++ XExtDisplayInfo *info = find_display(dpy);
++ xDRI2AuthenticateReply rep;
++ xDRI2AuthenticateReq *req;
++
++ DRI2CheckExtension(dpy, info, False);
++
++ LockDisplay(dpy);
++ GetReq(DRI2Authenticate, req);
++ req->reqType = info->codes->major_opcode;
++ req->dri2ReqType = X_DRI2Authenticate;
++ req->window = window;
++ req->magic = token;
++ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
++ UnlockDisplay(dpy);
++ SyncHandle();
++ return False;
++ }
++ UnlockDisplay(dpy);
++ SyncHandle();
++
++ return rep.authenticated ? True : False;
++}
++
++BOOL
++DRI2FallbackOpen(Display *dpy, int screen, int *device_fd)
++{
++ char *device;
++ int fd;
++ Window root = RootWindow(dpy, screen);
++ drm_auth_t auth;
++
++ if (!DRI2Connect(dpy, root, DRI2DriverDRI, &device))
++ return FALSE;
++
++ fd = open(device, O_RDWR);
++ HeapFree(GetProcessHeap(), 0, device);
++ if (fd < 0)
++ return FALSE;
++
++ if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth) != 0) {
++ close(fd);
++ return FALSE;
++ }
++
++ if (!DRI2Authenticate(dpy, root, auth.magic)) {
++ close(fd);
++ return FALSE;
++ }
++
++ *device_fd = fd;
++
++ return TRUE;
++}
++
++#endif
++
++
++BOOL
++DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height, int stride, int depth, int bpp, Pixmap *pixmap)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ Window root = RootWindow(dpy, screen);
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++
++ cookie = xcb_dri3_pixmap_from_buffer_checked(xcb_connection,
++ (*pixmap = xcb_generate_id(xcb_connection)),
++ root,
++ 0,
++ width, height, stride,
++ depth, bpp, fd);
++ error = xcb_request_check(xcb_connection, cookie); /* performs a flush */
++ if (error) {
++ ERR("Error using DRI3 to convert a DmaBufFd to pixmap\n");
++ return FALSE;
++ }
++ return TRUE;
++}
++
++BOOL
++DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height, int *stride, int *depth, int *bpp)
++{
++ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy);
++ xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
++ xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;
++
++ bp_cookie = xcb_dri3_buffer_from_pixmap(xcb_connection, pixmap);
++ bp_reply = xcb_dri3_buffer_from_pixmap_reply(xcb_connection, bp_cookie, NULL);
++ if (!bp_reply)
++ return FALSE;
++ *fd = xcb_dri3_buffer_from_pixmap_reply_fds(xcb_connection, bp_reply)[0];
++ *width = bp_reply->width;
++ *height = bp_reply->height;
++ *stride = bp_reply->stride;
++ *depth = bp_reply->depth;
++ *bpp = bp_reply->depth;
++ return TRUE;
++}
++
++struct PRESENTPriv {
++ xcb_connection_t *xcb_connection;
++ xcb_connection_t *xcb_connection_bis; /* to avoid libxcb thread bugs, use a different connection to present pixmaps */
++ XID window;
++ uint64_t last_msc;
++ uint64_t last_target;
++ uint32_t last_serial_given;
++ xcb_special_event_t *special_event;
++ PRESENTPixmapPriv *first_present_priv;
++ int pixmap_present_pending;
++ BOOL notify_with_serial_pending;
++ pthread_mutex_t mutex_present; /* protect readind/writing present_priv things */
++ pthread_mutex_t mutex_xcb_wait;
++ BOOL xcb_wait;
++};
++
++struct PRESENTPixmapPriv {
++ PRESENTpriv *present_priv;
++ Pixmap pixmap;
++ BOOL released;
++ unsigned int width;
++ unsigned int height;
++ unsigned int depth;
++ BOOL present_complete_pending;
++ uint32_t serial;
++#ifdef D3DADAPTER9_DRI2
++ struct {
++ BOOL is_dri2;
++ struct DRI2priv *dri2_priv;
++ GLuint fbo_read;
++ GLuint fbo_write;
++ GLuint texture_read;
++ GLuint texture_write;
++ } dri2_info;
++#endif
++ BOOL last_present_was_flip;
++ PRESENTPixmapPriv *next;
++};
++
++static PRESENTPixmapPriv *PRESENTFindPixmapPriv(PRESENTpriv *present_priv, uint32_t serial)
++{
++ PRESENTPixmapPriv *current = present_priv->first_present_priv;
++
++ while (current) {
++ if (current->serial == serial)
++ return current;
++ current = current->next;
++ }
++ return NULL;
++}
++
++static void PRESENThandle_events(PRESENTpriv *present_priv, xcb_present_generic_event_t *ge)
++{
++ PRESENTPixmapPriv *present_pixmap_priv = NULL;
++
++ switch (ge->evtype) {
++ case XCB_PRESENT_COMPLETE_NOTIFY: {
++ xcb_present_complete_notify_event_t *ce = (void *) ge;
++ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC) {
++ if (ce->serial)
++ present_priv->notify_with_serial_pending = FALSE;
++ free(ce);
++ return;
++ }
++ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ce->serial);
++ if (!present_pixmap_priv || ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
++ ERR("FATAL ERROR: PRESENT handling failed\n");
++ free(ce);
++ return;
++ }
++ present_pixmap_priv->present_complete_pending = FALSE;
++ switch (ce->mode) {
++ case XCB_PRESENT_COMPLETE_MODE_FLIP:
++ present_pixmap_priv->last_present_was_flip = TRUE;
++ break;
++ case XCB_PRESENT_COMPLETE_MODE_COPY:
++ present_pixmap_priv->last_present_was_flip = FALSE;
++ break;
++ }
++ present_priv->pixmap_present_pending--;
++ present_priv->last_msc = ce->msc;
++ break;
++ }
++ case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
++ xcb_present_idle_notify_event_t *ie = (void *) ge;
++ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ie->serial);
++ if (!present_pixmap_priv || present_pixmap_priv->pixmap != ie->pixmap) {
++ ERR("FATAL ERROR: PRESENT handling failed\n");
++ free(ie);
++ return;
++ }
++ present_pixmap_priv->released = TRUE;
++ break;
++ }
++ }
++ free(ge);
++}
++
++static void PRESENTflush_events(PRESENTpriv *present_priv, BOOL assert_no_other_thread_waiting)
++{
++ xcb_generic_event_t *ev;
++
++ if ((present_priv->xcb_wait && !assert_no_other_thread_waiting) || /* don't steal events to someone waiting */
++ !present_priv->special_event)
++ return;
++
++ while ((ev = xcb_poll_for_special_event(present_priv->xcb_connection, present_priv->special_event)) != NULL) {
++ PRESENThandle_events(present_priv, (void *) ev);
++ }
++}
++
++static BOOL PRESENTwait_events(PRESENTpriv *present_priv, BOOL allow_other_threads)
++{
++ xcb_generic_event_t *ev;
++
++ if (allow_other_threads) {
++ present_priv->xcb_wait = TRUE;
++ pthread_mutex_lock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ }
++ ev = xcb_wait_for_special_event(present_priv->xcb_connection, present_priv->special_event);
++ if (allow_other_threads) {
++ pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_lock(&present_priv->mutex_present);
++ present_priv->xcb_wait = FALSE;
++ }
++ if (!ev) {
++ ERR("FATAL error: xcb had an error\n");
++ return FALSE;
++ }
++
++ PRESENThandle_events(present_priv, (void *) ev);
++ return TRUE;
++}
++
++static struct xcb_connection_t *
++create_xcb_connection(Display *dpy)
++{
++ int screen_num = DefaultScreen(dpy);
++ xcb_connection_t *ret;
++ xcb_xfixes_query_version_cookie_t cookie;
++ xcb_xfixes_query_version_reply_t *rep;
++
++ ret = xcb_connect(DisplayString(dpy), &screen_num);
++ cookie = xcb_xfixes_query_version_unchecked(ret, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
++ rep = xcb_xfixes_query_version_reply(ret, cookie, NULL);
++ if (rep)
++ free(rep);
++ return ret;
++}
++
++BOOL
++PRESENTInit(Display *dpy, PRESENTpriv **present_priv)
++{
++ *present_priv = (PRESENTpriv *) calloc(1, sizeof(PRESENTpriv));
++ if (!*present_priv) {
++ return FALSE;
++ }
++ (*present_priv)->xcb_connection = create_xcb_connection(dpy);
++ (*present_priv)->xcb_connection_bis = create_xcb_connection(dpy);
++ pthread_mutex_init(&(*present_priv)->mutex_present, NULL);
++ pthread_mutex_init(&(*present_priv)->mutex_xcb_wait, NULL);
++ return TRUE;
++}
++
++static void PRESENTForceReleases(PRESENTpriv *present_priv)
++{
++ PRESENTPixmapPriv *current = NULL;
++
++ if (!present_priv->window)
++ return;
++
++ /* There should be no other thread listening for events here.
++ * This can happen when hDestWindowOverride changes without reset.
++ * This case should never happen, but can happen in theory.*/
++ if (present_priv->xcb_wait) {
++ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 0, 0, 0, 0);
++ xcb_flush(present_priv->xcb_connection);
++ pthread_mutex_lock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
++ /* the problem here is that we don't have access to the event the other thread got.
++ * It is either presented event, idle event or notify event.
++ */
++ while (present_priv->pixmap_present_pending >= 2)
++ PRESENTwait_events(present_priv, FALSE);
++ PRESENTflush_events(present_priv, TRUE);
++ /* Remaining events to come can be a pair of present/idle,
++ * or an idle, or nothing. To be sure we are after all pixmaps
++ * have been presented, add an event to the queue that can only
++ * be after the present event, then if we receive an event more,
++ * we are sure all pixmaps were presented */
++ present_priv->notify_with_serial_pending = TRUE;
++ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 1, present_priv->last_target + 5, 0, 0);
++ xcb_flush(present_priv->xcb_connection);
++ while (present_priv->notify_with_serial_pending)
++ PRESENTwait_events(present_priv, FALSE);
++ /* Now we are sure we are not expecting any new event */
++ } else {
++ while (present_priv->pixmap_present_pending) /* wait all sent pixmaps are presented */
++ PRESENTwait_events(present_priv, FALSE);
++ PRESENTflush_events(present_priv, TRUE); /* may be remaining idle event */
++ /* Since idle events are send with the complete events when it is not flips,
++ * we are not expecting any new event here */
++ }
++
++ current = present_priv->first_present_priv;
++ while (current) {
++ if (!current->released) {
++ if (!current->last_present_was_flip && !present_priv->xcb_wait) {
++ ERR("ERROR: a pixmap seems not released by PRESENT for no reason. Code bug.\n");
++ } else {
++ /* Present the same pixmap with a non-valid part to force the copy mode and the releases */
++ xcb_xfixes_region_t valid, update;
++ xcb_rectangle_t rect_update;
++ rect_update.x = 0;
++ rect_update.y = 0;
++ rect_update.width = 8;
++ rect_update.height = 1;
++ valid = xcb_generate_id(present_priv->xcb_connection);
++ update = xcb_generate_id(present_priv->xcb_connection);
++ xcb_xfixes_create_region(present_priv->xcb_connection, valid, 1, &rect_update);
++ xcb_xfixes_create_region(present_priv->xcb_connection, update, 1, &rect_update);
++ /* here we know the pixmap has been presented. Thus if it is on screen,
++ * the following request can only make it released by the server if it is not */
++ xcb_present_pixmap(present_priv->xcb_connection, present_priv->window,
++ current->pixmap, 0, valid, update, 0, 0, None, None,
++ None, XCB_PRESENT_OPTION_COPY | XCB_PRESENT_OPTION_ASYNC, 0, 0, 0, 0, NULL);
++ xcb_flush(present_priv->xcb_connection);
++ PRESENTwait_events(present_priv, FALSE); /* by assumption this can only be idle event */
++ PRESENTflush_events(present_priv, TRUE); /* Shoudln't be needed */
++ }
++ }
++ current = current->next;
++ }
++ /* Now all pixmaps are released (possibility if xcb_wait is true that one is not aware yet),
++ * and we don't expect any new Present event to come from Xserver */
++}
++
++static void PRESENTFreeXcbQueue(PRESENTpriv *present_priv)
++{
++ if (present_priv->window) {
++ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event);
++ present_priv->last_msc = 0;
++ present_priv->last_target = 0;
++ present_priv->special_event = NULL;
++ }
++}
++
++static BOOL PRESENTPrivChangeWindow(PRESENTpriv *present_priv, XID window)
++{
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++ xcb_present_event_t eid;
++
++ PRESENTForceReleases(present_priv);
++ PRESENTFreeXcbQueue(present_priv);
++ present_priv->window = window;
++
++ if (window) {
++ cookie = xcb_present_select_input_checked(present_priv->xcb_connection,
++ (eid = xcb_generate_id(present_priv->xcb_connection)),
++ window,
++ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|
++ XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
++ present_priv->special_event = xcb_register_for_special_xge(present_priv->xcb_connection,
++ &xcb_present_id,
++ eid, NULL);
++ error = xcb_request_check(present_priv->xcb_connection, cookie); /* performs a flush */
++ if (error || !present_priv->special_event) {
++ ERR("FAILED to use the X PRESENT extension. Was the destination a window ?\n");
++ if (present_priv->special_event)
++ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event);
++ present_priv->special_event = NULL;
++ present_priv->window = 0;
++ }
++ }
++ return (present_priv->window != 0);
++}
++
++/* Destroy the content, except the link and the struct mem */
++static void
++PRESENTDestroyPixmapContent(Display *dpy, PRESENTPixmapPriv *present_pixmap)
++{
++ XFreePixmap(dpy, present_pixmap->pixmap);
++#ifdef D3DADAPTER9_DRI2
++ if (present_pixmap->dri2_info.is_dri2) {
++ struct DRI2priv *dri2_priv = present_pixmap->dri2_info.dri2_priv;
++ EGLenum current_api;
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) {
++ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_read);
++ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_write);
++ glDeleteTextures(1, &present_pixmap->dri2_info.texture_read);
++ glDeleteTextures(1, &present_pixmap->dri2_info.texture_write);
++ } else {
++ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
++ }
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglBindAPI(current_api);
++ }
++#endif
++}
++
++void
++PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv)
++{
++ PRESENTPixmapPriv *current = NULL;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ PRESENTForceReleases(present_priv);
++
++ current = present_priv->first_present_priv;
++ while (current) {
++ PRESENTPixmapPriv *next = current->next;
++ PRESENTDestroyPixmapContent(dpy, current);
++ free(current);
++ current = next;
++ }
++
++ PRESENTFreeXcbQueue(present_priv);
++
++ xcb_disconnect(present_priv->xcb_connection);
++ xcb_disconnect(present_priv->xcb_connection_bis);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ pthread_mutex_destroy(&present_priv->mutex_present);
++ pthread_mutex_destroy(&present_priv->mutex_xcb_wait);
++
++ free(present_priv);
++}
++
++BOOL
++PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv)
++{
++ xcb_get_geometry_cookie_t cookie;
++ xcb_get_geometry_reply_t *reply;
++
++ cookie = xcb_get_geometry(present_priv->xcb_connection, pixmap);
++ reply = xcb_get_geometry_reply(present_priv->xcb_connection, cookie, NULL);
++
++ if (!reply)
++ return FALSE;
++
++ *present_pixmap_priv = (PRESENTPixmapPriv *) calloc(1, sizeof(PRESENTPixmapPriv));
++ if (!*present_pixmap_priv) {
++ free(reply);
++ return FALSE;
++ }
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ (*present_pixmap_priv)->released = TRUE;
++ (*present_pixmap_priv)->pixmap = pixmap;
++ (*present_pixmap_priv)->present_priv = present_priv;
++ (*present_pixmap_priv)->next = present_priv->first_present_priv;
++ (*present_pixmap_priv)->width = reply->width;
++ (*present_pixmap_priv)->height = reply->height;
++ (*present_pixmap_priv)->depth = reply->depth;
++#ifdef D3DADAPTER9_DRI2
++ (*present_pixmap_priv)->dri2_info.is_dri2 = FALSE;
++#endif
++ free(reply);
++
++ present_priv->last_serial_given++;
++ (*present_pixmap_priv)->serial = present_priv->last_serial_given;
++ present_priv->first_present_priv = *present_pixmap_priv;
++
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++#ifdef D3DADAPTER9_DRI2
++
++BOOL
++DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *dri2_priv,
++ int fd, int width, int height, int stride, int depth,
++ int bpp, PRESENTPixmapPriv **present_pixmap_priv)
++{
++ Window root = RootWindow(dri2_priv->dpy, DefaultScreen(dri2_priv->dpy));
++ Pixmap pixmap;
++ EGLImageKHR image;
++ GLuint texture_read, texture_write, fbo_read, fbo_write;
++ EGLint attribs[] = {
++ EGL_WIDTH, 0,
++ EGL_HEIGHT, 0,
++ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
++ EGL_DMA_BUF_PLANE0_FD_EXT, 0,
++ EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
++ EGL_DMA_BUF_PLANE0_PITCH_EXT, 0,
++ EGL_NONE
++ };
++ EGLenum current_api;
++ int status;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ pixmap = XCreatePixmap(dri2_priv->dpy, root, width, height, 24);
++ if (!pixmap)
++ goto fail;
++
++ attribs[1] = width;
++ attribs[3] = height;
++ attribs[7] = fd;
++ attribs[11] = stride;
++
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++
++ /* We bind the dma-buf to a EGLImage, then to a texture, and then to a fbo.
++ * Note that we can delete the EGLImage, but we shouldn't delete the texture,
++ * else the fbo is invalid */
++
++ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display,
++ EGL_NO_CONTEXT,
++ EGL_LINUX_DMA_BUF_EXT,
++ NULL, attribs);
++
++ if (image == EGL_NO_IMAGE_KHR)
++ goto fail;
++ close(fd);
++
++ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) {
++ glGenTextures(1, &texture_read);
++ glBindTexture(GL_TEXTURE_2D, texture_read);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image);
++ glGenFramebuffers(1, &fbo_read);
++ glBindFramebuffer(GL_FRAMEBUFFER, fbo_read);
++ glFramebufferTexture2D(GL_FRAMEBUFFER,
++ GL_COLOR_ATTACHMENT0,
++ GL_TEXTURE_2D, texture_read,
++ 0);
++ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
++ if (status != GL_FRAMEBUFFER_COMPLETE)
++ goto fail;
++ glBindTexture(GL_TEXTURE_2D, 0);
++ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image);
++
++ /* We bind a newly created pixmap (to which we want to copy the content)
++ * to an EGLImage, then to a texture, then to a fbo. */
++ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display,
++ dri2_priv->context,
++ EGL_NATIVE_PIXMAP_KHR,
++ (void *)pixmap, NULL);
++ if (image == EGL_NO_IMAGE_KHR)
++ goto fail;
++
++ glGenTextures(1, &texture_write);
++ glBindTexture(GL_TEXTURE_2D, texture_write);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image);
++ glGenFramebuffers(1, &fbo_write);
++ glBindFramebuffer(GL_FRAMEBUFFER, fbo_write);
++ glFramebufferTexture2D(GL_FRAMEBUFFER,
++ GL_COLOR_ATTACHMENT0,
++ GL_TEXTURE_2D, texture_write,
++ 0);
++ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
++ if (status != GL_FRAMEBUFFER_COMPLETE)
++ goto fail;
++ glBindTexture(GL_TEXTURE_2D, 0);
++ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image);
++ } else {
++ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
++ }
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++
++ *present_pixmap_priv = (PRESENTPixmapPriv *) calloc(1, sizeof(PRESENTPixmapPriv));
++ if (!*present_pixmap_priv) {
++ goto fail;
++ }
++
++ (*present_pixmap_priv)->released = TRUE;
++ (*present_pixmap_priv)->pixmap = pixmap;
++ (*present_pixmap_priv)->present_priv = present_priv;
++ (*present_pixmap_priv)->next = present_priv->first_present_priv;
++ (*present_pixmap_priv)->width = width;
++ (*present_pixmap_priv)->height = height;
++ (*present_pixmap_priv)->depth = depth;
++ (*present_pixmap_priv)->dri2_info.is_dri2 = TRUE;
++ (*present_pixmap_priv)->dri2_info.dri2_priv = dri2_priv;
++ (*present_pixmap_priv)->dri2_info.fbo_read = fbo_read;
++ (*present_pixmap_priv)->dri2_info.fbo_write = fbo_write;
++ (*present_pixmap_priv)->dri2_info.texture_read = texture_read;
++ (*present_pixmap_priv)->dri2_info.texture_write = texture_write;
++
++ present_priv->last_serial_given++;
++ (*present_pixmap_priv)->serial = present_priv->last_serial_given;
++ present_priv->first_present_priv = *present_pixmap_priv;
++
++ eglBindAPI(current_api);
++
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++fail:
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglBindAPI(current_api);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++}
++
++#endif
++
++BOOL
++PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++ PRESENTPixmapPriv *current;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) {
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++
++ if (present_priv->first_present_priv == present_pixmap_priv) {
++ present_priv->first_present_priv = present_pixmap_priv->next;
++ goto free_priv;
++ }
++
++ current = present_priv->first_present_priv;
++ while (current->next != present_pixmap_priv)
++ current = current->next;
++ current->next = present_pixmap_priv->next;
++free_priv:
++ PRESENTDestroyPixmapContent(dpy, present_pixmap_priv);
++ free(present_pixmap_priv);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++BOOL
++PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++
++ uint32_t v = 0;
++ xcb_gcontext_t gc;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ if (!present_priv->window) {
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++
++ xcb_create_gc(present_priv->xcb_connection,
++ (gc = xcb_generate_id(present_priv->xcb_connection)),
++ present_priv->window,
++ XCB_GC_GRAPHICS_EXPOSURES,
++ &v);
++ cookie = xcb_copy_area_checked(present_priv->xcb_connection,
++ present_priv->window,
++ present_pixmap_priv->pixmap,
++ gc,
++ 0, 0, 0, 0,
++ present_pixmap_priv->width,
++ present_pixmap_priv->height);
++ error = xcb_request_check(present_priv->xcb_connection, cookie);
++ xcb_free_gc(present_priv->xcb_connection, gc);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return (error != NULL);
++}
++
++BOOL
++PRESENTPixmap(Display *dpy, XID window,
++ PRESENTPixmapPriv *present_pixmap_priv, D3DPRESENT_PARAMETERS *pPresentationParameters,
++ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++#ifdef D3DADAPTER9_DRI2
++ struct DRI2priv *dri2_priv = present_pixmap_priv->dri2_info.dri2_priv;
++ EGLenum current_api;
++#endif
++ xcb_void_cookie_t cookie;
++ xcb_generic_error_t *error;
++ int64_t target_msc, presentationInterval;
++ xcb_xfixes_region_t valid, update;
++ int16_t x_off, y_off;
++ uint32_t options = XCB_PRESENT_OPTION_NONE;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ if (window != present_priv->window)
++ PRESENTPrivChangeWindow(present_priv, window);
++
++ if (!window) {
++ ERR("ERROR: Try to Present a pixmap on a NULL window\n");
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++
++ PRESENTflush_events(present_priv, FALSE);
++ if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) {
++ ERR("FATAL ERROR: Trying to Present a pixmap not released\n");
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++#ifdef D3DADAPTER9_DRI2
++ if (present_pixmap_priv->dri2_info.is_dri2) {
++ current_api = eglQueryAPI();
++ eglBindAPI(EGL_OPENGL_API);
++ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) {
++ glBindFramebuffer(GL_READ_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_read);
++ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_write);
++
++ glBlitFramebuffer(0, 0, present_pixmap_priv->width, present_pixmap_priv->height,
++ 0, 0, present_pixmap_priv->width, present_pixmap_priv->height,
++ GL_COLOR_BUFFER_BIT, GL_NEAREST);
++ glFlush(); /* Perhaps useless */
++ } else {
++ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError());
++ }
++ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
++ eglBindAPI(current_api);
++ }
++#endif
++ target_msc = present_priv->last_msc;
++ switch(pPresentationParameters->PresentationInterval) {
++ case D3DPRESENT_INTERVAL_DEFAULT:
++ case D3DPRESENT_INTERVAL_ONE:
++ presentationInterval = 1;
++ break;
++ case D3DPRESENT_INTERVAL_TWO:
++ presentationInterval = 2;
++ break;
++ case D3DPRESENT_INTERVAL_THREE:
++ presentationInterval = 3;
++ break;
++ case D3DPRESENT_INTERVAL_FOUR:
++ presentationInterval = 4;
++ break;
++ case D3DPRESENT_INTERVAL_IMMEDIATE:
++ default:
++ presentationInterval = 0;
++ options |= XCB_PRESENT_OPTION_ASYNC;
++ break;
++ }
++ target_msc += presentationInterval * (present_priv->pixmap_present_pending + 1);
++
++ /* Note: PRESENT defines some way to do partial copy:
++ * presentproto:
++ * 'x-off' and 'y-off' define the location in the window where
++ * the 0,0 location of the pixmap will be presented. valid-area
++ * and update-area are relative to the pixmap.
++ */
++ if (!pSourceRect && !pDestRect && !pDirtyRegion) {
++ valid = 0;
++ update = 0;
++ x_off = 0;
++ y_off = 0;
++ } else {
++ xcb_rectangle_t rect_update;
++ xcb_rectangle_t *rect_updates;
++ int i;
++
++ rect_update.x = 0;
++ rect_update.y = 0;
++ rect_update.width = present_pixmap_priv->width;
++ rect_update.height = present_pixmap_priv->height;
++ x_off = 0;
++ y_off = 0;
++ if (pSourceRect) {
++ x_off = -pSourceRect->left;
++ y_off = -pSourceRect->top;
++ rect_update.x = pSourceRect->left;
++ rect_update.y = pSourceRect->top;
++ rect_update.width = pSourceRect->right - pSourceRect->left;
++ rect_update.height = pSourceRect->bottom - pSourceRect->top;
++ }
++ if (pDestRect) {
++ x_off += pDestRect->left;
++ y_off += pDestRect->top;
++ rect_update.width = pDestRect->right - pDestRect->left;
++ rect_update.height = pDestRect->bottom - pDestRect->top;
++ /* Note: the size of pDestRect and pSourceRect are supposed to be the same size
++ * because the driver would have done things to assure that. */
++ }
++ valid = xcb_generate_id(present_priv->xcb_connection_bis);
++ update = xcb_generate_id(present_priv->xcb_connection_bis);
++ xcb_xfixes_create_region(present_priv->xcb_connection_bis, valid, 1, &rect_update);
++ if (pDirtyRegion && pDirtyRegion->rdh.nCount) {
++ rect_updates = (void *) calloc(pDirtyRegion->rdh.nCount, sizeof(xcb_rectangle_t));
++ for (i = 0; i < pDirtyRegion->rdh.nCount; i++)
++ {
++ RECT rc;
++ memcpy(&rc, pDirtyRegion->Buffer + i * sizeof(RECT), sizeof(RECT));
++ rect_update.x = rc.left;
++ rect_update.y = rc.top;
++ rect_update.width = rc.right - rc.left;
++ rect_update.height = rc.bottom - rc.top;
++ memcpy(rect_updates + i * sizeof(xcb_rectangle_t), &rect_update, sizeof(xcb_rectangle_t));
++ }
++ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, pDirtyRegion->rdh.nCount, rect_updates);
++ free(rect_updates);
++ } else
++ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, 1, &rect_update);
++ }
++ if (pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY)
++ options |= XCB_PRESENT_OPTION_COPY;
++ cookie = xcb_present_pixmap_checked(present_priv->xcb_connection_bis,
++ window,
++ present_pixmap_priv->pixmap,
++ present_pixmap_priv->serial,
++ valid, update, x_off, y_off,
++ None, None, None, options,
++ target_msc, 0, 0, 0, NULL);
++ error = xcb_request_check(present_priv->xcb_connection_bis, cookie); /* performs a flush */
++
++ if (update)
++ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, update);
++ if (valid)
++ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, valid);
++
++ if (error) {
++ xcb_get_geometry_cookie_t cookie_geom;
++ xcb_get_geometry_reply_t *reply;
++
++ cookie_geom = xcb_get_geometry(present_priv->xcb_connection_bis, window);
++ reply = xcb_get_geometry_reply(present_priv->xcb_connection_bis, cookie_geom, NULL);
++
++ ERR("Error using PRESENT. Here some debug info\n");
++ if (!reply) {
++ ERR("Error querying window info. Perhaps it doesn't exist anymore\n");
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++ ERR("Pixmap: width=%d, height=%d, depth=%d\n",
++ present_pixmap_priv->width, present_pixmap_priv->height,
++ present_pixmap_priv->depth);
++ ERR("Window: width=%d, height=%d, depth=%d, x=%d, y=%d\n",
++ (int) reply->width, (int) reply->height,
++ (int) reply->depth, (int) reply->x, (int) reply->y);
++ ERR("Present parameter: PresentationInterval=%d, BackBufferCount=%d, Pending presentations=%d\n",
++ pPresentationParameters->PresentationInterval,
++ pPresentationParameters->BackBufferCount,
++ present_priv->pixmap_present_pending
++ );
++ if (present_pixmap_priv->depth != reply->depth)
++ ERR("Depths are different. PRESENT needs the pixmap and the window have same depth\n");
++ free(reply);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++ present_priv->last_target = target_msc;
++ present_priv->pixmap_present_pending++;
++ present_pixmap_priv->present_complete_pending = TRUE;
++ present_pixmap_priv->released = FALSE;
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++BOOL
++PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv)
++{
++ PRESENTpriv *present_priv = present_pixmap_priv->present_priv;
++
++ pthread_mutex_lock(&present_priv->mutex_present);
++
++ PRESENTflush_events(present_priv, FALSE);
++
++ while (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) {
++ /* Note: following if should not happen because we'll never
++ * use two PRESENTWaitPixmapReleased in parallels on same window.
++ * However it would make it work in that case */
++ if (present_priv->xcb_wait) { /* we allow only one thread to dispatch events */
++ pthread_mutex_lock(&present_priv->mutex_xcb_wait);
++ /* here the other thread got an event but hasn't treated it yet */
++ pthread_mutex_unlock(&present_priv->mutex_xcb_wait);
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ Sleep(10); /* Let it treat the event */
++ pthread_mutex_lock(&present_priv->mutex_present);
++ } else if (!PRESENTwait_events(present_priv, TRUE)) {
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return FALSE;
++ }
++ }
++ pthread_mutex_unlock(&present_priv->mutex_present);
++ return TRUE;
++}
++
++#endif /* defined(SONAME_LIBXEXT) && defined(SONAME_LIBXFIXES) */
+diff --git a/dlls/winex11.drv/dri3.h b/dlls/winex11.drv/dri3.h
+new file mode 100644
+index 0000000..220e1b9
+--- /dev/null
++++ b/dlls/winex11.drv/dri3.h
+@@ -0,0 +1,110 @@
++/*
++ * 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
++
++#if defined(SONAME_LIBXEXT) && defined(SONAME_LIBXFIXES)
++
++#include <X11/extensions/Xfixes.h>
++#include <X11/Xlib.h>
++#include <X11/Xlib-xcb.h>
++#include <xcb/xcb.h>
++#include <xcb/dri3.h>
++#include <xcb/present.h>
++
++BOOL
++DRI3CheckExtension(Display *dpy, int major, int minor);
++
++#ifdef D3DADAPTER9_DRI2
++struct DRI2priv;
++
++BOOL
++DRI2FallbackInit(Display *dpy, struct DRI2priv **priv);
++
++void
++DRI2FallbackDestroy(struct DRI2priv *priv);
++
++BOOL
++DRI2FallbackCheckSupport(Display *dpy);
++#endif
++
++BOOL
++PRESENTCheckExtension(Display *dpy, int major, int minor);
++
++BOOL
++DRI3Open(Display *dpy, int screen, int *device_fd);
++
++#ifdef D3DADAPTER9_DRI2
++BOOL
++DRI2FallbackOpen(Display *dpy, int screen, int *device_fd);
++#endif
++
++BOOL
++DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height, int stride, int depth, int bpp, Pixmap *pixmap);
++
++BOOL
++DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height, int *stride, int *depth, int *bpp);
++
++typedef struct PRESENTPriv PRESENTpriv;
++typedef struct PRESENTPixmapPriv PRESENTPixmapPriv;
++
++BOOL
++PRESENTInit(Display *dpy, PRESENTpriv **present_priv);
++
++/* will clean properly and free all PRESENTPixmapPriv associated to PRESENTpriv.
++ * PRESENTPixmapPriv should not be freed by something else.
++ * If never a PRESENTPixmapPriv has to be destroyed,
++ * please destroy the current PRESENTpriv and create a new one.
++ * This will take care than all pixmaps are released */
++void
++PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv);
++
++BOOL
++PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv);
++
++#ifdef D3DADAPTER9_DRI2
++BOOL
++DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *priv,
++ int fd, int width, int height, int stride, int depth,
++ int bpp, PRESENTPixmapPriv **present_pixmap_priv);
++#endif
++
++BOOL
++PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv);
++
++BOOL
++PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv);
++
++BOOL
++PRESENTPixmap(Display *dpy, XID window,
++ PRESENTPixmapPriv *present_pixmap_priv, D3DPRESENT_PARAMETERS *pPresentationParameters,
++ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion);
++
++BOOL
++PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv);
++
++#endif /* defined(SONAME_LIBXEXT) && defined(SONAME_LIBXFIXES) */
++
++#endif /* __WINE_DRI3_H */
+diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c
+index 6bc4fb3..ddb6c15 100644
+--- a/dlls/winex11.drv/init.c
++++ b/dlls/winex11.drv/init.c
+@@ -365,6 +365,7 @@ static INT X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_d
+ {
+ struct x11drv_escape_get_drawable *data = out_data;
+ data->drawable = physDev->drawable;
++ data->dc_rect = physDev->dc_rect;
+ return TRUE;
+ }
+ break;
+@@ -464,6 +465,21 @@ static struct opengl_funcs * X11DRV_wine_get_wgl_driver( PHYSDEV dev, UINT versi
+ return ret;
+ }
+
++/**********************************************************************
++ * X11DRV_wine_get_d3dadapter_driver
++ */
++static struct d3dadapter_funcs * X11DRV_wine_get_d3dadapter_driver( PHYSDEV dev, UINT version )
++{
++ struct d3dadapter_funcs *ret;
++
++ if (!(ret = get_d3d_dri3_driver( version )))
++ {
++ dev = GET_NEXT_PHYSDEV( dev, wine_get_d3dadapter_driver );
++ ret = dev->funcs->wine_get_d3dadapter_driver( dev, version );
++ }
++ return ret;
++}
++
+
+ static const struct gdi_dc_funcs x11drv_funcs =
+ {
+@@ -594,6 +610,7 @@ static const struct gdi_dc_funcs x11drv_funcs =
+ X11DRV_UnrealizePalette, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ X11DRV_wine_get_wgl_driver, /* wine_get_wgl_driver */
++ X11DRV_wine_get_d3dadapter_driver, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV /* priority */
+ };
+
+diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
+index b7ec06e..353412e 100644
+--- a/dlls/winex11.drv/window.c
++++ b/dlls/winex11.drv/window.c
+@@ -1658,6 +1658,7 @@ void CDECL X11DRV_DestroyWindow( HWND hwnd )
+ struct x11drv_win_data *data;
+
+ destroy_gl_drawable( hwnd );
++ destroy_d3dadapter_drawable( hwnd );
+
+ if (!(data = get_win_data( hwnd ))) return;
+
+diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
+index cb4b0bb..322f457 100644
+--- a/dlls/winex11.drv/x11drv.h
++++ b/dlls/winex11.drv/x11drv.h
+@@ -220,6 +220,7 @@ extern BOOL shape_layered_windows DECLSPEC_HIDDEN;
+ extern const struct gdi_dc_funcs *X11DRV_XRender_Init(void) DECLSPEC_HIDDEN;
+
+ extern struct opengl_funcs *get_glx_driver(UINT) DECLSPEC_HIDDEN;
++extern struct d3dadapter_funcs *get_d3d_dri3_driver(UINT) DECLSPEC_HIDDEN;
+
+ /* IME support */
+ extern void IME_SetOpenStatus(BOOL fOpen) DECLSPEC_HIDDEN;
+@@ -292,6 +293,7 @@ struct x11drv_escape_get_drawable
+ Drawable drawable; /* X drawable */
+ Drawable gl_drawable; /* GL drawable */
+ int pixel_format; /* internal GL pixel format */
++ RECT dc_rect; /* DC rectangle relative to drawable */
+ };
+
+ struct x11drv_escape_flush_gl_drawable
+@@ -372,6 +374,7 @@ extern BOOL show_systray DECLSPEC_HIDDEN;
+ extern BOOL grab_pointer DECLSPEC_HIDDEN;
+ extern BOOL grab_fullscreen DECLSPEC_HIDDEN;
+ extern BOOL usexcomposite DECLSPEC_HIDDEN;
++extern BOOL usexfixes DECLSPEC_HIDDEN;
+ extern BOOL managed_mode DECLSPEC_HIDDEN;
+ extern BOOL decorated_mode DECLSPEC_HIDDEN;
+ extern BOOL private_color_map DECLSPEC_HIDDEN;
+@@ -573,6 +576,8 @@ extern void sync_gl_drawable( HWND hwnd, const RECT *visible_rect, const RECT *c
+ extern void set_gl_drawable_parent( HWND hwnd, HWND parent ) DECLSPEC_HIDDEN;
+ extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN;
+
++extern void destroy_d3dadapter_drawable( HWND hwnd ) DECLSPEC_HIDDEN;
++
+ extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN;
+ extern Window init_clip_window(void) DECLSPEC_HIDDEN;
+ extern void update_user_time( Time time ) DECLSPEC_HIDDEN;
+diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
+index 85c69bf..3a8c3a1 100644
+--- a/dlls/winex11.drv/x11drv_main.c
++++ b/dlls/winex11.drv/x11drv_main.c
+@@ -48,6 +48,7 @@
+
+ #include "x11drv.h"
+ #include "xcomposite.h"
++#include "xfixes.h"
+ #include "wine/server.h"
+ #include "wine/debug.h"
+ #include "wine/library.h"
+@@ -65,6 +66,7 @@ Window root_window;
+ BOOL usexvidmode = TRUE;
+ BOOL usexrandr = TRUE;
+ BOOL usexcomposite = TRUE;
++BOOL usexfixes = TRUE;
+ BOOL use_xkb = TRUE;
+ BOOL use_take_focus = TRUE;
+ BOOL use_primary_selection = FALSE;
+@@ -476,6 +478,54 @@ sym_not_found:
+ }
+ #endif /* defined(SONAME_LIBXCOMPOSITE) */
+
++#ifdef SONAME_LIBXFIXES
++
++#define MAKE_FUNCPTR(f) typeof(f) * p##f;
++MAKE_FUNCPTR(XFixesQueryExtension)
++MAKE_FUNCPTR(XFixesQueryVersion)
++MAKE_FUNCPTR(XFixesCreateRegion)
++MAKE_FUNCPTR(XFixesDestroyRegion)
++#undef MAKE_FUNCPTR
++
++int xfixes_event_base;
++int xfixes_error_base;
++
++static void X11DRV_XFixes_Init(void)
++{
++ void *xfixes_handle = wine_dlopen(SONAME_LIBXFIXES, RTLD_NOW, NULL, 0);
++ if (!xfixes_handle)
++ {
++ TRACE("Unable to open %s, XFixes disabled\n", SONAME_LIBXFIXES);
++ usexfixes = 0;
++ return;
++ }
++
++#define LOAD_FUNCPTR(f) \
++ if((p##f = wine_dlsym(xfixes_handle, #f, NULL, 0)) == NULL) \
++ goto sym_not_found;
++ LOAD_FUNCPTR(XFixesQueryExtension)
++ LOAD_FUNCPTR(XFixesQueryVersion)
++ LOAD_FUNCPTR(XFixesCreateRegion)
++ LOAD_FUNCPTR(XFixesDestroyRegion)
++#undef LOAD_FUNCPTR
++
++ if(!pXFixesQueryExtension(gdi_display, &xfixes_event_base,
++ &xfixes_error_base)) {
++ TRACE("XFixes extension could not be queried; disabled\n");
++ wine_dlclose(xfixes_handle, NULL, 0);
++ usexfixes = 0;
++ return;
++ }
++ TRACE("XFixes is up and running error_base = %d\n", xfixes_error_base);
++ return;
++
++sym_not_found:
++ TRACE("Unable to load function pointers from %s, XFixes disabled\n", SONAME_LIBXFIXES);
++ wine_dlclose(xfixes_handle, NULL, 0);
++ usexfixes = 0;
++}
++#endif /* SONAME_LIBXFIXES */
++
+ static void init_visuals( Display *display, int screen )
+ {
+ int count;
+@@ -582,6 +632,9 @@ static BOOL process_attach(void)
+ #ifdef SONAME_LIBXCOMPOSITE
+ X11DRV_XComposite_Init();
+ #endif
++#ifdef SONAME_LIBXFIXES
++ X11DRV_XFixes_Init();
++#endif
+ X11DRV_XInput2_Init();
+
+ #ifdef HAVE_XKB
+diff --git a/dlls/winex11.drv/xfixes.h b/dlls/winex11.drv/xfixes.h
+new file mode 100644
+index 0000000..cc7e287
+--- /dev/null
++++ b/dlls/winex11.drv/xfixes.h
+@@ -0,0 +1,39 @@
++/*
++ * Wine X11DRV XFixes interface
++ *
++ * Copyright 2007 Chris Robinson
++ * 2013 Joakim Sindholt
++ *
++ * 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_XFIXES_H
++#define __WINE_XFIXES_H
++
++#ifndef __WINE_CONFIG_H
++# error You must include config.h to use this header
++#endif
++
++#ifdef SONAME_LIBXFIXES
++
++#include <X11/extensions/Xfixes.h>
++#define MAKE_FUNCPTR(f) extern typeof(f) * p##f DECLSPEC_HIDDEN;
++MAKE_FUNCPTR(XFixesQueryExtension)
++MAKE_FUNCPTR(XFixesQueryVersion)
++MAKE_FUNCPTR(XFixesCreateRegion)
++MAKE_FUNCPTR(XFixesDestroyRegion)
++#undef MAKE_FUNCPTR
++
++#endif /* defined(SONAME_LIBXFIXES) */
++#endif /* __WINE_XFIXES_H */
+diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c
+index bc2ee40..01ed6e8 100644
+--- a/dlls/winex11.drv/xrender.c
++++ b/dlls/winex11.drv/xrender.c
+@@ -2275,6 +2275,7 @@ static const struct gdi_dc_funcs xrender_funcs =
+ NULL, /* pUnrealizePalette */
+ NULL, /* pWidenPath */
+ NULL, /* wine_get_wgl_driver */
++ NULL, /* wine_get_d3dadapter_driver */
+ GDI_PRIORITY_GRAPHICS_DRV + 10 /* priority */
+ };
+
+diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
+index edea9f8..143dc75 100644
+--- a/dlls/wininet/http.c
++++ b/dlls/wininet/http.c
+@@ -4877,6 +4877,16 @@ static char *build_ascii_request( const WCHAR *str, void *data, DWORD data_len,
+ return ret;
+ }
+
++static void set_content_length_header( http_request_t *request, DWORD len, DWORD flags )
++{
++ static const WCHAR fmtW[] =
++ {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','u','\r','\n',0};
++ WCHAR buf[sizeof(fmtW)/sizeof(fmtW[0]) + 10];
++
++ sprintfW( buf, fmtW, len );
++ HTTP_HttpAddRequestHeadersW( request, buf, ~0u, flags );
++}
++
+ /***********************************************************************
+ * HTTP_HttpSendRequestW (internal)
+ *
+@@ -4891,12 +4901,9 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
+ DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
+ DWORD dwContentLength, BOOL bEndRequest)
+ {
+- static const WCHAR szContentLength[] =
+- { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
+ BOOL redirected = FALSE, secure_proxy_connect = FALSE, loop_next;
+ LPWSTR requestString = NULL;
+ INT responseLen, cnt;
+- WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
+ DWORD res;
+
+ TRACE("--> %p\n", request);
+@@ -4912,8 +4919,7 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
+
+ if (dwContentLength || strcmpW(request->verb, szGET))
+ {
+- sprintfW(contentLengthStr, szContentLength, dwContentLength);
+- HTTP_HttpAddRequestHeadersW(request, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD_IF_NEW);
++ set_content_length_header(request, dwContentLength, HTTP_ADDREQ_FLAG_ADD_IF_NEW);
+ request->bytesToWrite = dwContentLength;
+ }
+ if (request->session->appInfo->agent)
+@@ -5002,6 +5008,10 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
+ {
+ static const WCHAR connectW[] = {'C','O','N','N','E','C','T',0};
+ const WCHAR *target = request->server->host_port;
++
++ if (HTTP_GetCustomHeaderIndex(request, szContent_Length, 0, TRUE) >= 0)
++ set_content_length_header(request, 0, HTTP_ADDREQ_FLAG_REPLACE);
++
+ requestString = build_request_header(request, connectW, target, g_szHttp1_1, TRUE);
+ }
+ else if (request->proxy && !(request->hdr.dwFlags & INTERNET_FLAG_SECURE))
+@@ -5011,7 +5021,12 @@ static DWORD HTTP_HttpSendRequestW(http_request_t *request, LPCWSTR lpszHeaders,
+ heap_free(url);
+ }
+ else
++ {
++ if (request->proxy && HTTP_GetCustomHeaderIndex(request, szContent_Length, 0, TRUE) >= 0)
++ set_content_length_header(request, dwContentLength, HTTP_ADDREQ_FLAG_REPLACE);
++
+ requestString = build_request_header(request, request->verb, request->path, request->version, TRUE);
++ }
+
+ TRACE("Request header -> %s\n", debugstr_w(requestString) );
+
+diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c
+index 973413a..410865d 100644
+--- a/dlls/wininet/tests/http.c
++++ b/dlls/wininet/tests/http.c
+@@ -2106,6 +2106,13 @@ static DWORD CALLBACK server_thread(LPVOID param)
+ else
+ send(c, notokmsg, sizeof notokmsg-1, 0);
+ }
++ if (strstr(buffer, "CONNECT "))
++ {
++ if (!strstr(buffer, "Content-Length: 0"))
++ send(c, notokmsg, sizeof notokmsg-1, 0);
++ else
++ send(c, proxymsg, sizeof proxymsg-1, 0);
++ }
+ if (strstr(buffer, "/test2"))
+ {
+ if (strstr(buffer, "Proxy-Authorization: Basic bWlrZToxMTAx"))
+@@ -2806,6 +2813,25 @@ static void test_proxy_direct(int port)
+ ok(r, "HttpQueryInfo failed\n");
+ ok(!strcmp(buffer, "200"), "proxy code wrong\n");
+
++ InternetCloseHandle(hr);
++ InternetCloseHandle(hc);
++ InternetCloseHandle(hi);
++
++ sprintf(buffer, "localhost:%d\n", port);
++ hi = InternetOpenA("winetest", INTERNET_OPEN_TYPE_PROXY, buffer, NULL, 0);
++ ok(hi != NULL, "InternetOpen failed\n");
++
++ hc = InternetConnectA(hi, "test.winehq.org", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
++ ok(hc != NULL, "InternetConnect failed\n");
++
++ hr = HttpOpenRequestA(hc, "POST", "/test2", NULL, NULL, NULL, INTERNET_FLAG_SECURE, 0);
++ ok(hr != NULL, "HttpOpenRequest failed\n");
++
++ r = HttpSendRequestA(hr, NULL, 0, (char *)"data", sizeof("data"));
++ ok(r, "HttpSendRequest failed %u\n", GetLastError());
++
++ test_status_code(hr, 407);
++
+ done:
+ InternetCloseHandle(hr);
+ InternetCloseHandle(hc);
+diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
+index 5cf3e0f..5098f85 100644
+--- a/dlls/ws2_32/socket.c
++++ b/dlls/ws2_32/socket.c
+@@ -7431,7 +7431,7 @@ INT WINAPI WS_inet_pton( INT family, PCSTR addr, PVOID buffer)
+ #ifdef HAVE_INET_PTON
+ int unixaf, ret;
+
+- TRACE("family %d, addr '%s', buffer (%p)\n", family, addr ? addr : "(null)", buffer);
++ TRACE("family %d, addr %s, buffer (%p)\n", family, debugstr_a(addr), buffer);
+
+ if (!addr || !buffer)
+ {
+@@ -7456,6 +7456,36 @@ INT WINAPI WS_inet_pton( INT family, PCSTR addr, PVOID buffer)
+ #endif
+ }
+
++/***********************************************************************
++* InetPtonW (WS2_32.@)
++*/
++INT WINAPI InetPtonW(INT family, PCWSTR addr, PVOID buffer)
++{
++ char *addrA;
++ int len;
++ INT ret;
++
++ TRACE("family %d, addr %s, buffer (%p)\n", family, debugstr_w(addr), buffer);
++
++ if (!addr)
++ {
++ SetLastError(WSAEFAULT);
++ return SOCKET_ERROR;
++ }
++
++ len = WideCharToMultiByte(CP_ACP, 0, addr, -1, NULL, 0, NULL, NULL);
++ if (!(addrA = HeapAlloc(GetProcessHeap(), 0, len)))
++ {
++ SetLastError(WSA_NOT_ENOUGH_MEMORY);
++ return SOCKET_ERROR;
++ }
++ WideCharToMultiByte(CP_ACP, 0, addr, -1, addrA, len, NULL, NULL);
++
++ ret = WS_inet_pton(family, addrA, buffer);
++
++ HeapFree(GetProcessHeap(), 0, addrA);
++ return ret;
++}
+
+ /***********************************************************************
+ * WSAStringToAddressA (WS2_32.80)
+diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
+index 8a0e375..7574631 100644
+--- a/dlls/ws2_32/tests/sock.c
++++ b/dlls/ws2_32/tests/sock.c
+@@ -67,7 +67,8 @@ static int (WINAPI *pgetaddrinfo)(LPCSTR,LPCSTR,const struct addrinfo *,struct
+ static void (WINAPI *pFreeAddrInfoW)(PADDRINFOW);
+ static int (WINAPI *pGetAddrInfoW)(LPCWSTR,LPCWSTR,const ADDRINFOW *,PADDRINFOW *);
+ static PCSTR (WINAPI *pInetNtop)(INT,LPVOID,LPSTR,ULONG);
+-static int (WINAPI *pInetPton)(INT,LPSTR,LPVOID);
++static int (WINAPI *pInetPtonA)(INT,LPCSTR,LPVOID);
++static int (WINAPI *pInetPtonW)(INT,LPWSTR,LPVOID);
+ static int (WINAPI *pWSALookupServiceBeginW)(LPWSAQUERYSETW,DWORD,LPHANDLE);
+ static int (WINAPI *pWSALookupServiceEnd)(HANDLE);
+ static int (WINAPI *pWSALookupServiceNextW)(HANDLE,DWORD,LPDWORD,LPWSAQUERYSETW);
+@@ -1159,7 +1160,8 @@ static void Init (void)
+ pFreeAddrInfoW = (void *)GetProcAddress(hws2_32, "FreeAddrInfoW");
+ pGetAddrInfoW = (void *)GetProcAddress(hws2_32, "GetAddrInfoW");
+ pInetNtop = (void *)GetProcAddress(hws2_32, "inet_ntop");
+- pInetPton = (void *)GetProcAddress(hws2_32, "inet_pton");
++ pInetPtonA = (void *)GetProcAddress(hws2_32, "inet_pton");
++ pInetPtonW = (void *)GetProcAddress(hws2_32, "InetPtonW");
+ pWSALookupServiceBeginW = (void *)GetProcAddress(hws2_32, "WSALookupServiceBeginW");
+ pWSALookupServiceEnd = (void *)GetProcAddress(hws2_32, "WSALookupServiceEnd");
+ pWSALookupServiceNextW = (void *)GetProcAddress(hws2_32, "WSALookupServiceNextW");
+@@ -4698,10 +4700,11 @@ static void test_inet_pton(void)
+ int i, ret;
+ DWORD err;
+ char buffer[64],str[64];
++ WCHAR printableW[64];
+ const char *ptr;
+
+ /* InetNtop and InetPton became available in Vista and Win2008 */
+- if (!pInetNtop || !pInetPton)
++ if (!pInetNtop || !pInetPtonA || !pInetPtonW)
+ {
+ win_skip("InetNtop and/or InetPton not present, not executing tests\n");
+ return;
+@@ -4710,7 +4713,7 @@ static void test_inet_pton(void)
+ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
+ {
+ WSASetLastError(0xdeadbeef);
+- ret = pInetPton(tests[i].family, (char *)tests[i].printable, buffer);
++ ret = pInetPtonA(tests[i].family, tests[i].printable, buffer);
+ ok (ret == tests[i].ret, "Test [%d]: Expected %d, got %d\n", i, tests[i].ret, ret);
+ if (tests[i].ret == -1)
+ {
+@@ -4731,6 +4734,25 @@ static void test_inet_pton(void)
+ ok (strcmp(ptr, tests[i].collapsed) == 0, "Test [%d]: Expected '%s', got '%s'\n",
+ i, tests[i].collapsed, ptr);
+ }
++
++ for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
++ {
++ if (tests[i].printable)
++ MultiByteToWideChar(CP_ACP, 0, tests[i].printable, -1, printableW,
++ sizeof(printableW) / sizeof(printableW[0]));
++ WSASetLastError(0xdeadbeef);
++ ret = pInetPtonW(tests[i].family, tests[i].printable ? printableW : NULL, buffer);
++ ok(ret == tests[i].ret, "Test [%d]: Expected %d, got %d\n", i, tests[i].ret, ret);
++ if (tests[i].ret == -1)
++ {
++ err = WSAGetLastError();
++ ok(tests[i].err == err, "Test [%d]: Expected 0x%x, got 0x%x\n", i, tests[i].err, err);
++ }
++ if (tests[i].ret != 1) continue;
++ ok(memcmp(buffer, tests[i].raw_data,
++ tests[i].family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr)) == 0,
++ "Test [%d]: Expected binary data differs\n", i);
++ }
+ }
+
+ static void test_ioctlsocket(void)
+diff --git a/dlls/ws2_32/ws2_32.spec b/dlls/ws2_32/ws2_32.spec
+index f7c6c2d..1b096b5 100644
+--- a/dlls/ws2_32/ws2_32.spec
++++ b/dlls/ws2_32/ws2_32.spec
+@@ -53,6 +53,7 @@
+ @ stdcall FreeAddrInfoW(ptr)
+ @ stdcall GetAddrInfoW(wstr wstr ptr ptr)
+ @ stdcall GetNameInfoW(ptr long ptr long ptr long long)
++@ stdcall InetPtonW(long wstr ptr)
+ @ stdcall WSApSetPostRoutine(ptr)
+ @ stdcall WPUCompleteOverlappedRequest(long ptr long long ptr)
+ @ stdcall WSAAccept(long ptr ptr ptr long)
+@@ -121,4 +122,4 @@
+ @ stdcall getaddrinfo(str str ptr ptr) WS_getaddrinfo
+ @ stdcall getnameinfo(ptr long ptr long ptr long long) WS_getnameinfo
+ @ stdcall inet_ntop(long ptr ptr long) WS_inet_ntop
+-@ stdcall inet_pton(long ptr ptr) WS_inet_pton
++@ stdcall inet_pton(long str ptr) WS_inet_pton
+diff --git a/dlls/xaudio2_3/Makefile.in b/dlls/xaudio2_3/Makefile.in
+new file mode 100644
+index 0000000..0e9e2f3
+--- /dev/null
++++ b/dlls/xaudio2_3/Makefile.in
+@@ -0,0 +1,7 @@
++MODULE = xaudio2_3.dll
++IMPORTS = ole32
++
++C_SRCS = \
++ xaudio_dll.c
++
++IDL_SRCS = xaudio_classes.idl
+diff --git a/dlls/xaudio2_3/xaudio2_3.spec b/dlls/xaudio2_3/xaudio2_3.spec
+new file mode 100644
+index 0000000..cb263d4
+--- /dev/null
++++ b/dlls/xaudio2_3/xaudio2_3.spec
+@@ -0,0 +1,4 @@
++@ stdcall -private DllCanUnloadNow()
++@ stdcall -private DllGetClassObject(ptr ptr ptr) xaudio2_7.DllGetClassObject
++@ stdcall -private DllRegisterServer()
++@ stdcall -private DllUnregisterServer()
+diff --git a/dlls/xaudio2_3/xaudio_classes.idl b/dlls/xaudio2_3/xaudio_classes.idl
+new file mode 100644
+index 0000000..c95fac0
+--- /dev/null
++++ b/dlls/xaudio2_3/xaudio_classes.idl
+@@ -0,0 +1,28 @@
++/*
++ * COM Classes for xaudio
++ *
++ * Copyright 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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
++ */
++
++#pragma makedep register
++
++[
++ helpstring("XAudio2.3 Class"),
++ threading(both),
++ uuid(4c5e637a-16c7-4de3-9c46-5ed22181962d)
++]
++coclass XAudio23 { interface IXAudio27; }
+diff --git a/dlls/xaudio2_3/xaudio_dll.c b/dlls/xaudio2_3/xaudio_dll.c
+new file mode 100644
+index 0000000..7c95c28
+--- /dev/null
++++ b/dlls/xaudio2_3/xaudio_dll.c
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (c) 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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 <stdarg.h>
++#include "windef.h"
++#include "winbase.h"
++#include "objbase.h"
++#include "rpcproxy.h"
++
++static HINSTANCE instance;
++
++BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved)
++{
++ switch (reason)
++ {
++ case DLL_PROCESS_ATTACH:
++ instance = hinstance;
++ DisableThreadLibraryCalls(hinstance);
++ break;
++ }
++ return TRUE;
++}
++
++HRESULT WINAPI DllCanUnloadNow(void)
++{
++ return S_FALSE;
++}
++
++HRESULT WINAPI DllRegisterServer(void)
++{
++ return __wine_register_resources(instance);
++}
++
++HRESULT WINAPI DllUnregisterServer(void)
++{
++ return __wine_unregister_resources(instance);
++}
+diff --git a/dlls/xaudio2_4/Makefile.in b/dlls/xaudio2_4/Makefile.in
+new file mode 100644
+index 0000000..9a9f19b
+--- /dev/null
++++ b/dlls/xaudio2_4/Makefile.in
+@@ -0,0 +1,7 @@
++MODULE = xaudio2_4.dll
++IMPORTS = ole32
++
++C_SRCS = \
++ xaudio_dll.c
++
++IDL_SRCS = xaudio_classes.idl
+diff --git a/dlls/xaudio2_4/xaudio2_4.spec b/dlls/xaudio2_4/xaudio2_4.spec
+new file mode 100644
+index 0000000..cb263d4
+--- /dev/null
++++ b/dlls/xaudio2_4/xaudio2_4.spec
+@@ -0,0 +1,4 @@
++@ stdcall -private DllCanUnloadNow()
++@ stdcall -private DllGetClassObject(ptr ptr ptr) xaudio2_7.DllGetClassObject
++@ stdcall -private DllRegisterServer()
++@ stdcall -private DllUnregisterServer()
+diff --git a/dlls/xaudio2_4/xaudio_classes.idl b/dlls/xaudio2_4/xaudio_classes.idl
+new file mode 100644
+index 0000000..26af295
+--- /dev/null
++++ b/dlls/xaudio2_4/xaudio_classes.idl
+@@ -0,0 +1,28 @@
++/*
++ * COM Classes for xaudio
++ *
++ * Copyright 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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
++ */
++
++#pragma makedep register
++
++[
++ helpstring("XAudio2.4 Class"),
++ threading(both),
++ uuid(03219e78-5bc3-44d1-b92e-f63d89cc6526)
++]
++coclass XAudio24 { interface IXAudio27; }
+diff --git a/dlls/xaudio2_4/xaudio_dll.c b/dlls/xaudio2_4/xaudio_dll.c
+new file mode 100644
+index 0000000..7c95c28
+--- /dev/null
++++ b/dlls/xaudio2_4/xaudio_dll.c
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (c) 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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 <stdarg.h>
++#include "windef.h"
++#include "winbase.h"
++#include "objbase.h"
++#include "rpcproxy.h"
++
++static HINSTANCE instance;
++
++BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved)
++{
++ switch (reason)
++ {
++ case DLL_PROCESS_ATTACH:
++ instance = hinstance;
++ DisableThreadLibraryCalls(hinstance);
++ break;
++ }
++ return TRUE;
++}
++
++HRESULT WINAPI DllCanUnloadNow(void)
++{
++ return S_FALSE;
++}
++
++HRESULT WINAPI DllRegisterServer(void)
++{
++ return __wine_register_resources(instance);
++}
++
++HRESULT WINAPI DllUnregisterServer(void)
++{
++ return __wine_unregister_resources(instance);
++}
+diff --git a/dlls/xaudio2_5/Makefile.in b/dlls/xaudio2_5/Makefile.in
+new file mode 100644
+index 0000000..6cc0565
+--- /dev/null
++++ b/dlls/xaudio2_5/Makefile.in
+@@ -0,0 +1,7 @@
++MODULE = xaudio2_5.dll
++IMPORTS = ole32
++
++C_SRCS = \
++ xaudio_dll.c
++
++IDL_SRCS = xaudio_classes.idl
+diff --git a/dlls/xaudio2_5/xaudio2_5.spec b/dlls/xaudio2_5/xaudio2_5.spec
+new file mode 100644
+index 0000000..cb263d4
+--- /dev/null
++++ b/dlls/xaudio2_5/xaudio2_5.spec
+@@ -0,0 +1,4 @@
++@ stdcall -private DllCanUnloadNow()
++@ stdcall -private DllGetClassObject(ptr ptr ptr) xaudio2_7.DllGetClassObject
++@ stdcall -private DllRegisterServer()
++@ stdcall -private DllUnregisterServer()
+diff --git a/dlls/xaudio2_5/xaudio_classes.idl b/dlls/xaudio2_5/xaudio_classes.idl
+new file mode 100644
+index 0000000..78d7c1e
+--- /dev/null
++++ b/dlls/xaudio2_5/xaudio_classes.idl
+@@ -0,0 +1,28 @@
++/*
++ * COM Classes for xaudio
++ *
++ * Copyright 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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
++ */
++
++#pragma makedep register
++
++[
++ helpstring("XAudio2.5 Class"),
++ threading(both),
++ uuid(4c9b6dde-6809-46e6-a278-9b6a97588670)
++]
++coclass XAudio25 { interface IXAudio27; }
+diff --git a/dlls/xaudio2_5/xaudio_dll.c b/dlls/xaudio2_5/xaudio_dll.c
+new file mode 100644
+index 0000000..7c95c28
+--- /dev/null
++++ b/dlls/xaudio2_5/xaudio_dll.c
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (c) 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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 <stdarg.h>
++#include "windef.h"
++#include "winbase.h"
++#include "objbase.h"
++#include "rpcproxy.h"
++
++static HINSTANCE instance;
++
++BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved)
++{
++ switch (reason)
++ {
++ case DLL_PROCESS_ATTACH:
++ instance = hinstance;
++ DisableThreadLibraryCalls(hinstance);
++ break;
++ }
++ return TRUE;
++}
++
++HRESULT WINAPI DllCanUnloadNow(void)
++{
++ return S_FALSE;
++}
++
++HRESULT WINAPI DllRegisterServer(void)
++{
++ return __wine_register_resources(instance);
++}
++
++HRESULT WINAPI DllUnregisterServer(void)
++{
++ return __wine_unregister_resources(instance);
++}
+diff --git a/dlls/xaudio2_6/Makefile.in b/dlls/xaudio2_6/Makefile.in
+new file mode 100644
+index 0000000..c56b079
+--- /dev/null
++++ b/dlls/xaudio2_6/Makefile.in
+@@ -0,0 +1,7 @@
++MODULE = xaudio2_6.dll
++IMPORTS = ole32
++
++C_SRCS = \
++ xaudio_dll.c
++
++IDL_SRCS = xaudio_classes.idl
+diff --git a/dlls/xaudio2_6/xaudio2_6.spec b/dlls/xaudio2_6/xaudio2_6.spec
+new file mode 100644
+index 0000000..cb263d4
+--- /dev/null
++++ b/dlls/xaudio2_6/xaudio2_6.spec
+@@ -0,0 +1,4 @@
++@ stdcall -private DllCanUnloadNow()
++@ stdcall -private DllGetClassObject(ptr ptr ptr) xaudio2_7.DllGetClassObject
++@ stdcall -private DllRegisterServer()
++@ stdcall -private DllUnregisterServer()
+diff --git a/dlls/xaudio2_6/xaudio_classes.idl b/dlls/xaudio2_6/xaudio_classes.idl
+new file mode 100644
+index 0000000..e54eed7
+--- /dev/null
++++ b/dlls/xaudio2_6/xaudio_classes.idl
+@@ -0,0 +1,28 @@
++/*
++ * COM Classes for xaudio
++ *
++ * Copyright 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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
++ */
++
++#pragma makedep register
++
++[
++ helpstring("XAudio2.6 Class"),
++ threading(both),
++ uuid(3eda9b49-2085-498b-9bb2-39a6778493de)
++]
++coclass XAudio26 { interface IXAudio27; }
+diff --git a/dlls/xaudio2_6/xaudio_dll.c b/dlls/xaudio2_6/xaudio_dll.c
+new file mode 100644
+index 0000000..7c95c28
+--- /dev/null
++++ b/dlls/xaudio2_6/xaudio_dll.c
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (c) 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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 <stdarg.h>
++#include "windef.h"
++#include "winbase.h"
++#include "objbase.h"
++#include "rpcproxy.h"
++
++static HINSTANCE instance;
++
++BOOL WINAPI DllMain(HINSTANCE hinstance, DWORD reason, LPVOID reserved)
++{
++ switch (reason)
++ {
++ case DLL_PROCESS_ATTACH:
++ instance = hinstance;
++ DisableThreadLibraryCalls(hinstance);
++ break;
++ }
++ return TRUE;
++}
++
++HRESULT WINAPI DllCanUnloadNow(void)
++{
++ return S_FALSE;
++}
++
++HRESULT WINAPI DllRegisterServer(void)
++{
++ return __wine_register_resources(instance);
++}
++
++HRESULT WINAPI DllUnregisterServer(void)
++{
++ return __wine_unregister_resources(instance);
++}
+diff --git a/dlls/xaudio2_7/Makefile.in b/dlls/xaudio2_7/Makefile.in
+index 5a09c82..acca92b 100644
+--- a/dlls/xaudio2_7/Makefile.in
++++ b/dlls/xaudio2_7/Makefile.in
+@@ -3,6 +3,7 @@ IMPORTS = advapi32 kernel32 ole32 user32 uuid
+ EXTRALIBS = $(OPENAL_LIBS)
+
+ C_SRCS = \
++ compat.c \
+ xaudio_dll.c
+
+ IDL_SRCS = xaudio_classes.idl
+diff --git a/dlls/xaudio2_7/compat.c b/dlls/xaudio2_7/compat.c
+new file mode 100644
+index 0000000..114463a
+--- /dev/null
++++ b/dlls/xaudio2_7/compat.c
+@@ -0,0 +1,1185 @@
++/*
++ * Copyright (c) 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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
++ *
++ ***************
++ *
++ * Some versions of XAudio2 add or remove functions to the COM vtables, or
++ * incompatibly change structures. This file provides implementations of the
++ * older XAudio2 versions onto the new XAudio2 APIs.
++ *
++ * Below is a list of significant changes to the main XAudio2 interfaces and
++ * API. There may be further changes to effects and other parts that Wine
++ * doesn't currently implement.
++ *
++ * 2.0
++ * Initial version
++ *
++ * 2.1
++ * Change CLSID_XAudio2
++ * Re-order Error codes
++ * Change XAUDIO2_LOOP_INFINITE
++ * Change struct XAUDIO2_PERFORMANCE_DATA
++ * Change IXAudio2Voice::GetOutputMatrix return value to void
++ * Add parameter to IXAudio2VoiceCallback::OnVoiceProcessingPassStart
++ * Change struct XAPO_REGISTRATION_PROPERTIES. CAREFUL when using! Not all
++ * implementations of IXAPO are Wine implementations.
++ *
++ * 2.2
++ * Change CLSID_XAudio2
++ * No ABI break
++ *
++ * 2.3
++ * Change CLSID_XAudio2
++ * ABI break:
++ * Change struct XAUDIO2_PERFORMANCE_DATA
++ *
++ * 2.4
++ * Change CLSID_XAudio2
++ * ABI break:
++ * Add IXAudio2Voice::SetOutputFilterParameters
++ * Add IXAudio2Voice::GetOutputFilterParameters
++ * Add IXAudio2SourceVoice::SetSourceSampleRate
++ * Change struct XAUDIO2_VOICE_SENDS
++ *
++ * 2.5
++ * Change CLSID_XAudio2
++ * No ABI break
++ *
++ * 2.6
++ * Change CLSID_XAudio2
++ * No ABI break
++ *
++ * 2.7
++ * Change CLSID_XAudio2
++ * No ABI break
++ *
++ * 2.8
++ * Remove CLSID_XAudio2
++ * Change IID_IXAudio2
++ * Add xaudio2_8.XAudio2Create
++ * ABI break:
++ * Remove IXAudio2::GetDeviceCount
++ * Remove IXAudio2::GetDeviceDetails
++ * Remove IXAudio2::Initialize
++ * Change parameter of IXAudio2::CreateMasteringVoice
++ * Add Flags parameter to IXAudio2SourceVoice::GetState
++ * Add IXAudio2MasteringVoice::GetChannelMask
++ */
++
++#include "config.h"
++
++#define NONAMELESSUNION
++#define NONAMELESSSTRUCT
++#define COBJMACROS
++
++#include <stdarg.h>
++
++#include "xaudio_private.h"
++
++#include "wine/debug.h"
++
++WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
++
++XA2SourceImpl *impl_from_IXAudio27SourceVoice(IXAudio27SourceVoice *iface)
++{
++ return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio27SourceVoice_iface);
++}
++
++static void WINAPI XA27SRC_GetVoiceDetails(IXAudio27SourceVoice *iface,
++ XAUDIO2_VOICE_DETAILS *pVoiceDetails)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_GetVoiceDetails(&This->IXAudio2SourceVoice_iface, pVoiceDetails);
++}
++
++static HRESULT WINAPI XA27SRC_SetOutputVoices(IXAudio27SourceVoice *iface,
++ const XAUDIO2_VOICE_SENDS *pSendList)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetOutputVoices(&This->IXAudio2SourceVoice_iface, pSendList);
++}
++
++static HRESULT WINAPI XA27SRC_SetEffectChain(IXAudio27SourceVoice *iface,
++ const XAUDIO2_EFFECT_CHAIN *pEffectChain)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetEffectChain(&This->IXAudio2SourceVoice_iface, pEffectChain);
++}
++
++static HRESULT WINAPI XA27SRC_EnableEffect(IXAudio27SourceVoice *iface,
++ UINT32 EffectIndex, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_EnableEffect(&This->IXAudio2SourceVoice_iface, EffectIndex, OperationSet);
++}
++
++static HRESULT WINAPI XA27SRC_DisableEffect(IXAudio27SourceVoice *iface,
++ UINT32 EffectIndex, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_DisableEffect(&This->IXAudio2SourceVoice_iface, EffectIndex, OperationSet);
++}
++
++static void WINAPI XA27SRC_GetEffectState(IXAudio27SourceVoice *iface,
++ UINT32 EffectIndex, BOOL *pEnabled)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ IXAudio2SourceVoice_GetEffectState(&This->IXAudio2SourceVoice_iface, EffectIndex, pEnabled);
++}
++
++static HRESULT WINAPI XA27SRC_SetEffectParameters(IXAudio27SourceVoice *iface,
++ UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetEffectParameters(&This->IXAudio2SourceVoice_iface,
++ EffectIndex, pParameters, ParametersByteSize, OperationSet);
++}
++
++static HRESULT WINAPI XA27SRC_GetEffectParameters(IXAudio27SourceVoice *iface,
++ UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_GetEffectParameters(&This->IXAudio2SourceVoice_iface,
++ EffectIndex, pParameters, ParametersByteSize);
++}
++
++static HRESULT WINAPI XA27SRC_SetFilterParameters(IXAudio27SourceVoice *iface,
++ const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetFilterParameters(&This->IXAudio2SourceVoice_iface,
++ pParameters, OperationSet);
++}
++
++static void WINAPI XA27SRC_GetFilterParameters(IXAudio27SourceVoice *iface,
++ XAUDIO2_FILTER_PARAMETERS *pParameters)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ IXAudio2SourceVoice_GetFilterParameters(&This->IXAudio2SourceVoice_iface, pParameters);
++}
++
++static HRESULT WINAPI XA27SRC_SetOutputFilterParameters(IXAudio27SourceVoice *iface,
++ IXAudio2Voice *pDestinationVoice,
++ const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetOutputFilterParameters(&This->IXAudio2SourceVoice_iface,
++ pDestinationVoice, pParameters, OperationSet);
++}
++
++static void WINAPI XA27SRC_GetOutputFilterParameters(IXAudio27SourceVoice *iface,
++ IXAudio2Voice *pDestinationVoice,
++ XAUDIO2_FILTER_PARAMETERS *pParameters)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ IXAudio2SourceVoice_GetOutputFilterParameters(&This->IXAudio2SourceVoice_iface,
++ pDestinationVoice, pParameters);
++}
++
++static HRESULT WINAPI XA27SRC_SetVolume(IXAudio27SourceVoice *iface, float Volume,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetVolume(&This->IXAudio2SourceVoice_iface, Volume,
++ OperationSet);
++}
++
++static void WINAPI XA27SRC_GetVolume(IXAudio27SourceVoice *iface, float *pVolume)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ IXAudio2SourceVoice_GetVolume(&This->IXAudio2SourceVoice_iface, pVolume);
++}
++
++static HRESULT WINAPI XA27SRC_SetChannelVolumes(IXAudio27SourceVoice *iface,
++ UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetChannelVolumes(&This->IXAudio2SourceVoice_iface, Channels,
++ pVolumes, OperationSet);
++}
++
++static void WINAPI XA27SRC_GetChannelVolumes(IXAudio27SourceVoice *iface,
++ UINT32 Channels, float *pVolumes)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ IXAudio2SourceVoice_GetChannelVolumes(&This->IXAudio2SourceVoice_iface, Channels,
++ pVolumes);
++}
++
++static HRESULT WINAPI XA27SRC_SetOutputMatrix(IXAudio27SourceVoice *iface,
++ IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
++ UINT32 DestinationChannels, const float *pLevelMatrix,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetOutputMatrix(&This->IXAudio2SourceVoice_iface,
++ pDestinationVoice, SourceChannels, DestinationChannels,
++ pLevelMatrix, OperationSet);
++}
++
++static void WINAPI XA27SRC_GetOutputMatrix(IXAudio27SourceVoice *iface,
++ IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
++ UINT32 DestinationChannels, float *pLevelMatrix)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ IXAudio2SourceVoice_GetOutputMatrix(&This->IXAudio2SourceVoice_iface, pDestinationVoice,
++ SourceChannels, DestinationChannels, pLevelMatrix);
++}
++
++static void WINAPI XA27SRC_DestroyVoice(IXAudio27SourceVoice *iface)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ IXAudio2SourceVoice_DestroyVoice(&This->IXAudio2SourceVoice_iface);
++}
++
++static HRESULT WINAPI XA27SRC_Start(IXAudio27SourceVoice *iface, UINT32 Flags,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_Start(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
++}
++
++static HRESULT WINAPI XA27SRC_Stop(IXAudio27SourceVoice *iface, UINT32 Flags,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_Stop(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
++}
++
++static HRESULT WINAPI XA27SRC_SubmitSourceBuffer(IXAudio27SourceVoice *iface,
++ const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SubmitSourceBuffer(&This->IXAudio2SourceVoice_iface, pBuffer,
++ pBufferWMA);
++}
++
++static HRESULT WINAPI XA27SRC_FlushSourceBuffers(IXAudio27SourceVoice *iface)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_FlushSourceBuffers(&This->IXAudio2SourceVoice_iface);
++}
++
++static HRESULT WINAPI XA27SRC_Discontinuity(IXAudio27SourceVoice *iface)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_Discontinuity(&This->IXAudio2SourceVoice_iface);
++}
++
++static HRESULT WINAPI XA27SRC_ExitLoop(IXAudio27SourceVoice *iface, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_ExitLoop(&This->IXAudio2SourceVoice_iface, OperationSet);
++}
++
++static void WINAPI XA27SRC_GetState(IXAudio27SourceVoice *iface,
++ XAUDIO2_VOICE_STATE *pVoiceState)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_GetState(&This->IXAudio2SourceVoice_iface, pVoiceState, 0);
++}
++
++static HRESULT WINAPI XA27SRC_SetFrequencyRatio(IXAudio27SourceVoice *iface,
++ float Ratio, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetFrequencyRatio(&This->IXAudio2SourceVoice_iface, Ratio, OperationSet);
++}
++
++static void WINAPI XA27SRC_GetFrequencyRatio(IXAudio27SourceVoice *iface, float *pRatio)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_GetFrequencyRatio(&This->IXAudio2SourceVoice_iface, pRatio);
++}
++
++static HRESULT WINAPI XA27SRC_SetSourceSampleRate(
++ IXAudio27SourceVoice *iface,
++ UINT32 NewSourceSampleRate)
++{
++ XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
++ return IXAudio2SourceVoice_SetSourceSampleRate(&This->IXAudio2SourceVoice_iface, NewSourceSampleRate);
++}
++
++const IXAudio27SourceVoiceVtbl XAudio27SourceVoice_Vtbl = {
++ XA27SRC_GetVoiceDetails,
++ XA27SRC_SetOutputVoices,
++ XA27SRC_SetEffectChain,
++ XA27SRC_EnableEffect,
++ XA27SRC_DisableEffect,
++ XA27SRC_GetEffectState,
++ XA27SRC_SetEffectParameters,
++ XA27SRC_GetEffectParameters,
++ XA27SRC_SetFilterParameters,
++ XA27SRC_GetFilterParameters,
++ XA27SRC_SetOutputFilterParameters,
++ XA27SRC_GetOutputFilterParameters,
++ XA27SRC_SetVolume,
++ XA27SRC_GetVolume,
++ XA27SRC_SetChannelVolumes,
++ XA27SRC_GetChannelVolumes,
++ XA27SRC_SetOutputMatrix,
++ XA27SRC_GetOutputMatrix,
++ XA27SRC_DestroyVoice,
++ XA27SRC_Start,
++ XA27SRC_Stop,
++ XA27SRC_SubmitSourceBuffer,
++ XA27SRC_FlushSourceBuffers,
++ XA27SRC_Discontinuity,
++ XA27SRC_ExitLoop,
++ XA27SRC_GetState,
++ XA27SRC_SetFrequencyRatio,
++ XA27SRC_GetFrequencyRatio,
++ XA27SRC_SetSourceSampleRate
++};
++
++static inline IXAudio2Impl *impl_from_IXAudio27(IXAudio27 *iface)
++{
++ return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio27_iface);
++}
++
++static HRESULT WINAPI XA27_QueryInterface(IXAudio27 *iface, REFIID riid,
++ void **ppvObject)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_QueryInterface(&This->IXAudio2_iface, riid, ppvObject);
++}
++
++static ULONG WINAPI XA27_AddRef(IXAudio27 *iface)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_AddRef(&This->IXAudio2_iface);
++}
++
++static ULONG WINAPI XA27_Release(IXAudio27 *iface)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_Release(&This->IXAudio2_iface);
++}
++
++static HRESULT WINAPI XA27_GetDeviceCount(IXAudio27 *iface, UINT32 *pCount)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++
++ TRACE("%p, %p\n", This, pCount);
++
++ *pCount = This->ndevs;
++
++ return S_OK;
++}
++
++static HRESULT WINAPI XA27_GetDeviceDetails(IXAudio27 *iface, UINT32 index,
++ XAUDIO2_DEVICE_DETAILS *pDeviceDetails)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ HRESULT hr;
++ IMMDevice *dev;
++ IAudioClient *client;
++ IPropertyStore *ps;
++ WAVEFORMATEX *wfx;
++ PROPVARIANT var;
++
++ TRACE("%p, %u, %p\n", This, index, pDeviceDetails);
++
++ if(index >= This->ndevs)
++ return E_INVALIDARG;
++
++ hr = IMMDeviceEnumerator_GetDevice(This->devenum, This->devids[index], &dev);
++ if(FAILED(hr)){
++ WARN("GetDevice failed: %08x\n", hr);
++ return hr;
++ }
++
++ hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER,
++ NULL, (void**)&client);
++ if(FAILED(hr)){
++ WARN("Activate failed: %08x\n", hr);
++ IMMDevice_Release(dev);
++ return hr;
++ }
++
++ hr = IMMDevice_OpenPropertyStore(dev, STGM_READ, &ps);
++ if(FAILED(hr)){
++ WARN("OpenPropertyStore failed: %08x\n", hr);
++ IAudioClient_Release(client);
++ IMMDevice_Release(dev);
++ return hr;
++ }
++
++ PropVariantInit(&var);
++
++ hr = IPropertyStore_GetValue(ps, (PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &var);
++ if(FAILED(hr)){
++ WARN("GetValue failed: %08x\n", hr);
++ goto done;
++ }
++
++ lstrcpynW(pDeviceDetails->DisplayName, var.u.pwszVal, sizeof(pDeviceDetails->DisplayName)/sizeof(WCHAR));
++
++ PropVariantClear(&var);
++
++ hr = IAudioClient_GetMixFormat(client, &wfx);
++ if(FAILED(hr)){
++ WARN("GetMixFormat failed: %08x\n", hr);
++ goto done;
++ }
++
++ lstrcpyW(pDeviceDetails->DeviceID, This->devids[index]);
++
++ if(index == 0)
++ pDeviceDetails->Role = GlobalDefaultDevice;
++ else
++ pDeviceDetails->Role = NotDefaultDevice;
++
++ if(sizeof(WAVEFORMATEX) + wfx->cbSize > sizeof(pDeviceDetails->OutputFormat)){
++ FIXME("AudioClient format is too large to fit into WAVEFORMATEXTENSIBLE!\n");
++ CoTaskMemFree(wfx);
++ hr = E_FAIL;
++ goto done;
++ }
++ memcpy(&pDeviceDetails->OutputFormat, wfx, sizeof(WAVEFORMATEX) + wfx->cbSize);
++
++ CoTaskMemFree(wfx);
++
++done:
++ IPropertyStore_Release(ps);
++ IAudioClient_Release(client);
++ IMMDevice_Release(dev);
++
++ return hr;
++}
++
++static HRESULT WINAPI XA27_Initialize(IXAudio27 *iface, UINT32 flags,
++ XAUDIO2_PROCESSOR processor)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ TRACE("(%p)->(0x%x, 0x%x)\n", This, flags, processor);
++ return S_OK;
++}
++
++static HRESULT WINAPI XA27_RegisterForCallbacks(IXAudio27 *iface,
++ IXAudio2EngineCallback *pCallback)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_RegisterForCallbacks(&This->IXAudio2_iface, pCallback);
++}
++
++static void WINAPI XA27_UnregisterForCallbacks(IXAudio27 *iface,
++ IXAudio2EngineCallback *pCallback)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ IXAudio2_UnregisterForCallbacks(&This->IXAudio2_iface, pCallback);
++}
++
++static HRESULT WINAPI XA27_CreateSourceVoice(IXAudio27 *iface,
++ IXAudio2SourceVoice **ppSourceVoice, const WAVEFORMATEX *pSourceFormat,
++ UINT32 flags, float maxFrequencyRatio,
++ IXAudio2VoiceCallback *pCallback, const XAUDIO2_VOICE_SENDS *pSendList,
++ const XAUDIO2_EFFECT_CHAIN *pEffectChain)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_CreateSourceVoice(&This->IXAudio2_iface, ppSourceVoice,
++ pSourceFormat, flags, maxFrequencyRatio, pCallback, pSendList,
++ pEffectChain);
++}
++
++static HRESULT WINAPI XA27_CreateSubmixVoice(IXAudio27 *iface,
++ IXAudio2SubmixVoice **ppSubmixVoice, UINT32 inputChannels,
++ UINT32 inputSampleRate, UINT32 flags, UINT32 processingStage,
++ const XAUDIO2_VOICE_SENDS *pSendList,
++ const XAUDIO2_EFFECT_CHAIN *pEffectChain)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_CreateSubmixVoice(&This->IXAudio2_iface, ppSubmixVoice,
++ inputChannels, inputSampleRate, flags, processingStage, pSendList,
++ pEffectChain);
++}
++
++static HRESULT WINAPI XA27_CreateMasteringVoice(IXAudio27 *iface,
++ IXAudio2MasteringVoice **ppMasteringVoice, UINT32 inputChannels,
++ UINT32 inputSampleRate, UINT32 flags, UINT32 deviceIndex,
++ const XAUDIO2_EFFECT_CHAIN *pEffectChain)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++
++ TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p)\n", This, ppMasteringVoice,
++ inputChannels, inputSampleRate, flags, deviceIndex,
++ pEffectChain);
++
++ if(deviceIndex >= This->ndevs)
++ return E_INVALIDARG;
++
++ return IXAudio2_CreateMasteringVoice(&This->IXAudio2_iface, ppMasteringVoice,
++ inputChannels, inputSampleRate, flags, This->devids[deviceIndex],
++ pEffectChain, AudioCategory_GameEffects);
++}
++
++static HRESULT WINAPI XA27_StartEngine(IXAudio27 *iface)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_StartEngine(&This->IXAudio2_iface);
++}
++
++static void WINAPI XA27_StopEngine(IXAudio27 *iface)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_StopEngine(&This->IXAudio2_iface);
++}
++
++static HRESULT WINAPI XA27_CommitChanges(IXAudio27 *iface, UINT32 operationSet)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_CommitChanges(&This->IXAudio2_iface, operationSet);
++}
++
++static void WINAPI XA27_GetPerformanceData(IXAudio27 *iface,
++ XAUDIO2_PERFORMANCE_DATA *pPerfData)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_GetPerformanceData(&This->IXAudio2_iface, pPerfData);
++}
++
++static void WINAPI XA27_SetDebugConfiguration(IXAudio27 *iface,
++ const XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
++ void *pReserved)
++{
++ IXAudio2Impl *This = impl_from_IXAudio27(iface);
++ return IXAudio2_SetDebugConfiguration(&This->IXAudio2_iface,
++ pDebugConfiguration, pReserved);
++}
++
++const IXAudio27Vtbl XAudio27_Vtbl = {
++ XA27_QueryInterface,
++ XA27_AddRef,
++ XA27_Release,
++ XA27_GetDeviceCount,
++ XA27_GetDeviceDetails,
++ XA27_Initialize,
++ XA27_RegisterForCallbacks,
++ XA27_UnregisterForCallbacks,
++ XA27_CreateSourceVoice,
++ XA27_CreateSubmixVoice,
++ XA27_CreateMasteringVoice,
++ XA27_StartEngine,
++ XA27_StopEngine,
++ XA27_CommitChanges,
++ XA27_GetPerformanceData,
++ XA27_SetDebugConfiguration
++};
++
++XA2SourceImpl *impl_from_IXAudio23SourceVoice(IXAudio23SourceVoice *iface)
++{
++ return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio23SourceVoice_iface);
++}
++
++static void WINAPI XA23SRC_GetVoiceDetails(IXAudio23SourceVoice *iface,
++ XAUDIO2_VOICE_DETAILS *pVoiceDetails)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_GetVoiceDetails(&This->IXAudio2SourceVoice_iface, pVoiceDetails);
++}
++
++static HRESULT WINAPI XA23SRC_SetOutputVoices(IXAudio23SourceVoice *iface,
++ const XAUDIO23_VOICE_SENDS *pSendList)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ XAUDIO2_VOICE_SENDS sends;
++ HRESULT hr;
++ DWORD i;
++
++ TRACE("%p, %p\n", This, pSendList);
++
++ sends.SendCount = pSendList->OutputCount;
++ sends.pSends = HeapAlloc(GetProcessHeap(), 0, sends.SendCount * sizeof(*sends.pSends));
++ for(i = 0; i < sends.SendCount; ++i){
++ sends.pSends[i].Flags = 0;
++ sends.pSends[i].pOutputVoice = pSendList->pOutputVoices[i];
++ }
++
++ hr = IXAudio2SourceVoice_SetOutputVoices(&This->IXAudio2SourceVoice_iface, &sends);
++
++ HeapFree(GetProcessHeap(), 0, sends.pSends);
++
++ return hr;
++}
++
++static HRESULT WINAPI XA23SRC_SetEffectChain(IXAudio23SourceVoice *iface,
++ const XAUDIO2_EFFECT_CHAIN *pEffectChain)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_SetEffectChain(&This->IXAudio2SourceVoice_iface, pEffectChain);
++}
++
++static HRESULT WINAPI XA23SRC_EnableEffect(IXAudio23SourceVoice *iface,
++ UINT32 EffectIndex, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_EnableEffect(&This->IXAudio2SourceVoice_iface,
++ EffectIndex, OperationSet);
++}
++
++static HRESULT WINAPI XA23SRC_DisableEffect(IXAudio23SourceVoice *iface,
++ UINT32 EffectIndex, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_DisableEffect(&This->IXAudio2SourceVoice_iface,
++ EffectIndex, OperationSet);
++}
++
++static void WINAPI XA23SRC_GetEffectState(IXAudio23SourceVoice *iface,
++ UINT32 EffectIndex, BOOL *pEnabled)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_GetEffectState(&This->IXAudio2SourceVoice_iface,
++ EffectIndex, pEnabled);
++}
++
++static HRESULT WINAPI XA23SRC_SetEffectParameters(IXAudio23SourceVoice *iface,
++ UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_SetEffectParameters(&This->IXAudio2SourceVoice_iface,
++ EffectIndex, pParameters, ParametersByteSize, OperationSet);
++}
++
++static HRESULT WINAPI XA23SRC_GetEffectParameters(IXAudio23SourceVoice *iface,
++ UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_GetEffectParameters(&This->IXAudio2SourceVoice_iface,
++ EffectIndex, pParameters, ParametersByteSize);
++}
++
++static HRESULT WINAPI XA23SRC_SetFilterParameters(IXAudio23SourceVoice *iface,
++ const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_SetFilterParameters(&This->IXAudio2SourceVoice_iface,
++ pParameters, OperationSet);
++}
++
++static void WINAPI XA23SRC_GetFilterParameters(IXAudio23SourceVoice *iface,
++ XAUDIO2_FILTER_PARAMETERS *pParameters)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_GetFilterParameters(&This->IXAudio2SourceVoice_iface, pParameters);
++}
++
++static HRESULT WINAPI XA23SRC_SetVolume(IXAudio23SourceVoice *iface,
++ float Volume, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_SetVolume(&This->IXAudio2SourceVoice_iface,
++ Volume, OperationSet);
++}
++
++static void WINAPI XA23SRC_GetVolume(IXAudio23SourceVoice *iface,
++ float *pVolume)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_GetVolume(&This->IXAudio2SourceVoice_iface, pVolume);
++}
++
++static HRESULT WINAPI XA23SRC_SetChannelVolumes(IXAudio23SourceVoice *iface,
++ UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_SetChannelVolumes(&This->IXAudio2SourceVoice_iface,
++ Channels, pVolumes, OperationSet);
++}
++
++static void WINAPI XA23SRC_GetChannelVolumes(IXAudio23SourceVoice *iface,
++ UINT32 Channels, float *pVolumes)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_GetChannelVolumes(&This->IXAudio2SourceVoice_iface,
++ Channels, pVolumes);
++}
++
++static HRESULT WINAPI XA23SRC_SetOutputMatrix(IXAudio23SourceVoice *iface,
++ IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
++ UINT32 DestinationChannels, const float *pLevelMatrix,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_SetOutputMatrix(&This->IXAudio2SourceVoice_iface,
++ pDestinationVoice, SourceChannels, DestinationChannels,
++ pLevelMatrix, OperationSet);
++}
++
++static void WINAPI XA23SRC_GetOutputMatrix(IXAudio23SourceVoice *iface,
++ IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
++ UINT32 DestinationChannels, float *pLevelMatrix)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_GetOutputMatrix(&This->IXAudio2SourceVoice_iface,
++ pDestinationVoice, SourceChannels, DestinationChannels,
++ pLevelMatrix);
++}
++
++static void WINAPI XA23SRC_DestroyVoice(IXAudio23SourceVoice *iface)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_DestroyVoice(&This->IXAudio2SourceVoice_iface);
++}
++
++static HRESULT WINAPI XA23SRC_Start(IXAudio23SourceVoice *iface, UINT32 Flags,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_Start(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
++}
++
++static HRESULT WINAPI XA23SRC_Stop(IXAudio23SourceVoice *iface, UINT32 Flags,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_Stop(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
++}
++
++static HRESULT WINAPI XA23SRC_SubmitSourceBuffer(IXAudio23SourceVoice *iface,
++ const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_SubmitSourceBuffer(&This->IXAudio2SourceVoice_iface,
++ pBuffer, pBufferWMA);
++}
++
++static HRESULT WINAPI XA23SRC_FlushSourceBuffers(IXAudio23SourceVoice *iface)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_FlushSourceBuffers(&This->IXAudio2SourceVoice_iface);
++}
++
++static HRESULT WINAPI XA23SRC_Discontinuity(IXAudio23SourceVoice *iface)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_Discontinuity(&This->IXAudio2SourceVoice_iface);
++}
++
++static HRESULT WINAPI XA23SRC_ExitLoop(IXAudio23SourceVoice *iface,
++ UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_ExitLoop(&This->IXAudio2SourceVoice_iface, OperationSet);
++}
++
++static void WINAPI XA23SRC_GetState(IXAudio23SourceVoice *iface,
++ XAUDIO2_VOICE_STATE *pVoiceState)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_GetState(&This->IXAudio2SourceVoice_iface, pVoiceState, 0);
++}
++
++static HRESULT WINAPI XA23SRC_SetFrequencyRatio(IXAudio23SourceVoice *iface,
++ float Ratio, UINT32 OperationSet)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_SetFrequencyRatio(&This->IXAudio2SourceVoice_iface,
++ Ratio, OperationSet);
++}
++
++static void WINAPI XA23SRC_GetFrequencyRatio(IXAudio23SourceVoice *iface,
++ float *pRatio)
++{
++ XA2SourceImpl *This = impl_from_IXAudio23SourceVoice(iface);
++ return IXAudio2SourceVoice_GetFrequencyRatio(&This->IXAudio2SourceVoice_iface, pRatio);
++}
++
++const IXAudio23SourceVoiceVtbl XAudio23SourceVoice_Vtbl = {
++ XA23SRC_GetVoiceDetails,
++ XA23SRC_SetOutputVoices,
++ XA23SRC_SetEffectChain,
++ XA23SRC_EnableEffect,
++ XA23SRC_DisableEffect,
++ XA23SRC_GetEffectState,
++ XA23SRC_SetEffectParameters,
++ XA23SRC_GetEffectParameters,
++ XA23SRC_SetFilterParameters,
++ XA23SRC_GetFilterParameters,
++ XA23SRC_SetVolume,
++ XA23SRC_GetVolume,
++ XA23SRC_SetChannelVolumes,
++ XA23SRC_GetChannelVolumes,
++ XA23SRC_SetOutputMatrix,
++ XA23SRC_GetOutputMatrix,
++ XA23SRC_DestroyVoice,
++ XA23SRC_Start,
++ XA23SRC_Stop,
++ XA23SRC_SubmitSourceBuffer,
++ XA23SRC_FlushSourceBuffers,
++ XA23SRC_Discontinuity,
++ XA23SRC_ExitLoop,
++ XA23SRC_GetState,
++ XA23SRC_SetFrequencyRatio,
++ XA23SRC_GetFrequencyRatio,
++};
++
++XA2SubmixImpl *impl_from_IXAudio23SubmixVoice(IXAudio23SubmixVoice *iface)
++{
++ return CONTAINING_RECORD(iface, XA2SubmixImpl, IXAudio23SubmixVoice_iface);
++}
++
++static void WINAPI XA23SUB_GetVoiceDetails(IXAudio23SubmixVoice *iface,
++ XAUDIO2_VOICE_DETAILS *pVoiceDetails)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_GetVoiceDetails(&This->IXAudio2SubmixVoice_iface, pVoiceDetails);
++}
++
++static HRESULT WINAPI XA23SUB_SetOutputVoices(IXAudio23SubmixVoice *iface,
++ const XAUDIO23_VOICE_SENDS *pSendList)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ XAUDIO2_VOICE_SENDS sends;
++ HRESULT hr;
++ DWORD i;
++
++ TRACE("%p, %p\n", This, pSendList);
++
++ sends.SendCount = pSendList->OutputCount;
++ sends.pSends = HeapAlloc(GetProcessHeap(), 0, sends.SendCount * sizeof(*sends.pSends));
++ for(i = 0; i < sends.SendCount; ++i){
++ sends.pSends[i].Flags = 0;
++ sends.pSends[i].pOutputVoice = pSendList->pOutputVoices[i];
++ }
++
++ hr = IXAudio2SubmixVoice_SetOutputVoices(&This->IXAudio2SubmixVoice_iface, &sends);
++
++ HeapFree(GetProcessHeap(), 0, sends.pSends);
++
++ return hr;
++}
++
++static HRESULT WINAPI XA23SUB_SetEffectChain(IXAudio23SubmixVoice *iface,
++ const XAUDIO2_EFFECT_CHAIN *pEffectChain)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_SetEffectChain(&This->IXAudio2SubmixVoice_iface, pEffectChain);
++}
++
++static HRESULT WINAPI XA23SUB_EnableEffect(IXAudio23SubmixVoice *iface,
++ UINT32 EffectIndex, UINT32 OperationSet)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_EnableEffect(&This->IXAudio2SubmixVoice_iface,
++ EffectIndex, OperationSet);
++}
++
++static HRESULT WINAPI XA23SUB_DisableEffect(IXAudio23SubmixVoice *iface,
++ UINT32 EffectIndex, UINT32 OperationSet)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_DisableEffect(&This->IXAudio2SubmixVoice_iface,
++ EffectIndex, OperationSet);
++}
++
++static void WINAPI XA23SUB_GetEffectState(IXAudio23SubmixVoice *iface,
++ UINT32 EffectIndex, BOOL *pEnabled)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_GetEffectState(&This->IXAudio2SubmixVoice_iface,
++ EffectIndex, pEnabled);
++}
++
++static HRESULT WINAPI XA23SUB_SetEffectParameters(IXAudio23SubmixVoice *iface,
++ UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
++ UINT32 OperationSet)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_SetEffectParameters(&This->IXAudio2SubmixVoice_iface,
++ EffectIndex, pParameters, ParametersByteSize, OperationSet);
++}
++
++static HRESULT WINAPI XA23SUB_GetEffectParameters(IXAudio23SubmixVoice *iface,
++ UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_GetEffectParameters(&This->IXAudio2SubmixVoice_iface,
++ EffectIndex, pParameters, ParametersByteSize);
++}
++
++static HRESULT WINAPI XA23SUB_SetFilterParameters(IXAudio23SubmixVoice *iface,
++ const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_SetFilterParameters(&This->IXAudio2SubmixVoice_iface,
++ pParameters, OperationSet);
++}
++
++static void WINAPI XA23SUB_GetFilterParameters(IXAudio23SubmixVoice *iface,
++ XAUDIO2_FILTER_PARAMETERS *pParameters)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_GetFilterParameters(&This->IXAudio2SubmixVoice_iface, pParameters);
++}
++
++static HRESULT WINAPI XA23SUB_SetVolume(IXAudio23SubmixVoice *iface,
++ float Volume, UINT32 OperationSet)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_SetVolume(&This->IXAudio2SubmixVoice_iface,
++ Volume, OperationSet);
++}
++
++static void WINAPI XA23SUB_GetVolume(IXAudio23SubmixVoice *iface,
++ float *pVolume)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_GetVolume(&This->IXAudio2SubmixVoice_iface, pVolume);
++}
++
++static HRESULT WINAPI XA23SUB_SetChannelVolumes(IXAudio23SubmixVoice *iface,
++ UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_SetChannelVolumes(&This->IXAudio2SubmixVoice_iface,
++ Channels, pVolumes, OperationSet);
++}
++
++static void WINAPI XA23SUB_GetChannelVolumes(IXAudio23SubmixVoice *iface,
++ UINT32 Channels, float *pVolumes)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_GetChannelVolumes(&This->IXAudio2SubmixVoice_iface,
++ Channels, pVolumes);
++}
++
++static HRESULT WINAPI XA23SUB_SetOutputMatrix(IXAudio23SubmixVoice *iface,
++ IXAudio2Voice *pDestinationVoice, UINT32 SubmixChannels,
++ UINT32 DestinationChannels, const float *pLevelMatrix,
++ UINT32 OperationSet)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_SetOutputMatrix(&This->IXAudio2SubmixVoice_iface,
++ pDestinationVoice, SubmixChannels, DestinationChannels,
++ pLevelMatrix, OperationSet);
++}
++
++static void WINAPI XA23SUB_GetOutputMatrix(IXAudio23SubmixVoice *iface,
++ IXAudio2Voice *pDestinationVoice, UINT32 SubmixChannels,
++ UINT32 DestinationChannels, float *pLevelMatrix)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_GetOutputMatrix(&This->IXAudio2SubmixVoice_iface,
++ pDestinationVoice, SubmixChannels, DestinationChannels,
++ pLevelMatrix);
++}
++
++static void WINAPI XA23SUB_DestroyVoice(IXAudio23SubmixVoice *iface)
++{
++ XA2SubmixImpl *This = impl_from_IXAudio23SubmixVoice(iface);
++ return IXAudio2SubmixVoice_DestroyVoice(&This->IXAudio2SubmixVoice_iface);
++}
++
++const IXAudio23SubmixVoiceVtbl XAudio23SubmixVoice_Vtbl = {
++ XA23SUB_GetVoiceDetails,
++ XA23SUB_SetOutputVoices,
++ XA23SUB_SetEffectChain,
++ XA23SUB_EnableEffect,
++ XA23SUB_DisableEffect,
++ XA23SUB_GetEffectState,
++ XA23SUB_SetEffectParameters,
++ XA23SUB_GetEffectParameters,
++ XA23SUB_SetFilterParameters,
++ XA23SUB_GetFilterParameters,
++ XA23SUB_SetVolume,
++ XA23SUB_GetVolume,
++ XA23SUB_SetChannelVolumes,
++ XA23SUB_GetChannelVolumes,
++ XA23SUB_SetOutputMatrix,
++ XA23SUB_GetOutputMatrix,
++ XA23SUB_DestroyVoice
++};
++
++IXAudio2Impl *impl_from_IXAudio23MasteringVoice(IXAudio23MasteringVoice *iface)
++{
++ return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio23MasteringVoice_iface);
++}
++
++static void WINAPI XA23M_GetVoiceDetails(IXAudio23MasteringVoice *iface,
++ XAUDIO2_VOICE_DETAILS *pVoiceDetails)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_GetVoiceDetails(&This->IXAudio2MasteringVoice_iface, pVoiceDetails);
++}
++
++static HRESULT WINAPI XA23M_SetOutputVoices(IXAudio23MasteringVoice *iface,
++ const XAUDIO23_VOICE_SENDS *pSendList)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ XAUDIO2_VOICE_SENDS sends;
++ HRESULT hr;
++ DWORD i;
++
++ TRACE("%p, %p\n", This, pSendList);
++
++ sends.SendCount = pSendList->OutputCount;
++ sends.pSends = HeapAlloc(GetProcessHeap(), 0, sends.SendCount * sizeof(*sends.pSends));
++ for(i = 0; i < sends.SendCount; ++i){
++ sends.pSends[i].Flags = 0;
++ sends.pSends[i].pOutputVoice = pSendList->pOutputVoices[i];
++ }
++
++ hr = IXAudio2MasteringVoice_SetOutputVoices(&This->IXAudio2MasteringVoice_iface, &sends);
++
++ HeapFree(GetProcessHeap(), 0, sends.pSends);
++
++ return hr;
++}
++
++static HRESULT WINAPI XA23M_SetEffectChain(IXAudio23MasteringVoice *iface,
++ const XAUDIO2_EFFECT_CHAIN *pEffectChain)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_SetEffectChain(&This->IXAudio2MasteringVoice_iface, pEffectChain);
++}
++
++static HRESULT WINAPI XA23M_EnableEffect(IXAudio23MasteringVoice *iface,
++ UINT32 EffectIndex, UINT32 OperationSet)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_EnableEffect(&This->IXAudio2MasteringVoice_iface,
++ EffectIndex, OperationSet);
++}
++
++static HRESULT WINAPI XA23M_DisableEffect(IXAudio23MasteringVoice *iface,
++ UINT32 EffectIndex, UINT32 OperationSet)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_DisableEffect(&This->IXAudio2MasteringVoice_iface,
++ EffectIndex, OperationSet);
++}
++
++static void WINAPI XA23M_GetEffectState(IXAudio23MasteringVoice *iface,
++ UINT32 EffectIndex, BOOL *pEnabled)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_GetEffectState(&This->IXAudio2MasteringVoice_iface,
++ EffectIndex, pEnabled);
++}
++
++static HRESULT WINAPI XA23M_SetEffectParameters(IXAudio23MasteringVoice *iface,
++ UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
++ UINT32 OperationSet)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_SetEffectParameters(&This->IXAudio2MasteringVoice_iface,
++ EffectIndex, pParameters, ParametersByteSize, OperationSet);
++}
++
++static HRESULT WINAPI XA23M_GetEffectParameters(IXAudio23MasteringVoice *iface,
++ UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_GetEffectParameters(&This->IXAudio2MasteringVoice_iface,
++ EffectIndex, pParameters, ParametersByteSize);
++}
++
++static HRESULT WINAPI XA23M_SetFilterParameters(IXAudio23MasteringVoice *iface,
++ const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_SetFilterParameters(&This->IXAudio2MasteringVoice_iface,
++ pParameters, OperationSet);
++}
++
++static void WINAPI XA23M_GetFilterParameters(IXAudio23MasteringVoice *iface,
++ XAUDIO2_FILTER_PARAMETERS *pParameters)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_GetFilterParameters(&This->IXAudio2MasteringVoice_iface, pParameters);
++}
++
++static HRESULT WINAPI XA23M_SetVolume(IXAudio23MasteringVoice *iface,
++ float Volume, UINT32 OperationSet)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_SetVolume(&This->IXAudio2MasteringVoice_iface,
++ Volume, OperationSet);
++}
++
++static void WINAPI XA23M_GetVolume(IXAudio23MasteringVoice *iface,
++ float *pVolume)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_GetVolume(&This->IXAudio2MasteringVoice_iface, pVolume);
++}
++
++static HRESULT WINAPI XA23M_SetChannelVolumes(IXAudio23MasteringVoice *iface,
++ UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_SetChannelVolumes(&This->IXAudio2MasteringVoice_iface,
++ Channels, pVolumes, OperationSet);
++}
++
++static void WINAPI XA23M_GetChannelVolumes(IXAudio23MasteringVoice *iface,
++ UINT32 Channels, float *pVolumes)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_GetChannelVolumes(&This->IXAudio2MasteringVoice_iface,
++ Channels, pVolumes);
++}
++
++static HRESULT WINAPI XA23M_SetOutputMatrix(IXAudio23MasteringVoice *iface,
++ IXAudio2Voice *pDestinationVoice, UINT32 MasteringChannels,
++ UINT32 DestinationChannels, const float *pLevelMatrix,
++ UINT32 OperationSet)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_SetOutputMatrix(&This->IXAudio2MasteringVoice_iface,
++ pDestinationVoice, MasteringChannels, DestinationChannels,
++ pLevelMatrix, OperationSet);
++}
++
++static void WINAPI XA23M_GetOutputMatrix(IXAudio23MasteringVoice *iface,
++ IXAudio2Voice *pDestinationVoice, UINT32 MasteringChannels,
++ UINT32 DestinationChannels, float *pLevelMatrix)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_GetOutputMatrix(&This->IXAudio2MasteringVoice_iface,
++ pDestinationVoice, MasteringChannels, DestinationChannels,
++ pLevelMatrix);
++}
++
++static void WINAPI XA23M_DestroyVoice(IXAudio23MasteringVoice *iface)
++{
++ IXAudio2Impl *This = impl_from_IXAudio23MasteringVoice(iface);
++ return IXAudio2MasteringVoice_DestroyVoice(&This->IXAudio2MasteringVoice_iface);
++}
++
++const IXAudio23MasteringVoiceVtbl XAudio23MasteringVoice_Vtbl = {
++ XA23M_GetVoiceDetails,
++ XA23M_SetOutputVoices,
++ XA23M_SetEffectChain,
++ XA23M_EnableEffect,
++ XA23M_DisableEffect,
++ XA23M_GetEffectState,
++ XA23M_SetEffectParameters,
++ XA23M_GetEffectParameters,
++ XA23M_SetFilterParameters,
++ XA23M_GetFilterParameters,
++ XA23M_SetVolume,
++ XA23M_GetVolume,
++ XA23M_SetChannelVolumes,
++ XA23M_GetChannelVolumes,
++ XA23M_SetOutputMatrix,
++ XA23M_GetOutputMatrix,
++ XA23M_DestroyVoice
++};
+diff --git a/dlls/xaudio2_7/xaudio_dll.c b/dlls/xaudio2_7/xaudio_dll.c
+index 835426f..5453d25 100644
+--- a/dlls/xaudio2_7/xaudio_dll.c
++++ b/dlls/xaudio2_7/xaudio_dll.c
+@@ -22,29 +22,14 @@
+ #define NONAMELESSUNION
+ #define COBJMACROS
+
+-#include "windef.h"
+-#include "winbase.h"
+-#include "winuser.h"
++#include "initguid.h"
++
++#include "xaudio_private.h"
+
+ #include "ole2.h"
+ #include "rpcproxy.h"
+
+ #include "wine/debug.h"
+-#include "wine/list.h"
+-#include <propsys.h>
+-#include "initguid.h"
+-
+-#include "mmsystem.h"
+-#include "xaudio2.h"
+-#include "xaudio2fx.h"
+-#include "xapo.h"
+-#include "devpkey.h"
+-#include "mmdeviceapi.h"
+-#include "audioclient.h"
+-
+-#include <AL/al.h>
+-#include <AL/alc.h>
+-#include <AL/alext.h>
+
+ WINE_DEFAULT_DEBUG_CHANNEL(xaudio2);
+
+@@ -127,122 +112,21 @@ HRESULT WINAPI DllUnregisterServer(void)
+ return __wine_unregister_resources(instance);
+ }
+
+-typedef struct _XA2Buffer {
+- XAUDIO2_BUFFER xa2buffer;
+- DWORD offs_bytes;
+- UINT32 latest_al_buf, looped, loop_end_bytes, play_end_bytes, cur_end_bytes;
+-} XA2Buffer;
+-
+-typedef struct _IXAudio2Impl IXAudio2Impl;
+-
+-typedef struct _XA2SourceImpl {
+- IXAudio27SourceVoice IXAudio27SourceVoice_iface;
+- IXAudio2SourceVoice IXAudio2SourceVoice_iface;
+-
+- IXAudio2Impl *xa2;
+-
+- BOOL in_use;
+-
+- CRITICAL_SECTION lock;
+-
+- WAVEFORMATEX *fmt;
+- ALenum al_fmt;
+- UINT32 submit_blocksize;
+-
+- IXAudio2VoiceCallback *cb;
+-
+- DWORD nsends;
+- XAUDIO2_SEND_DESCRIPTOR *sends;
+-
+- BOOL running;
+-
+- UINT64 played_frames;
+-
+- XA2Buffer buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
+- UINT32 first_buf, cur_buf, nbufs, in_al_bytes;
+-
+- ALuint al_src;
+- /* most cases will only need about 4 AL buffers, but some corner cases
+- * could require up to MAX_QUEUED_BUFFERS */
+- ALuint al_bufs[XAUDIO2_MAX_QUEUED_BUFFERS];
+- DWORD first_al_buf, al_bufs_used;
+-
+- struct list entry;
+-} XA2SourceImpl;
+-
+ static XA2SourceImpl *impl_from_IXAudio2SourceVoice(IXAudio2SourceVoice *iface)
+ {
+ return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio2SourceVoice_iface);
+ }
+
+-static XA2SourceImpl *impl_from_IXAudio27SourceVoice(IXAudio27SourceVoice *iface)
+-{
+- return CONTAINING_RECORD(iface, XA2SourceImpl, IXAudio27SourceVoice_iface);
+-}
+-
+-typedef struct _XA2SubmixImpl {
+- IXAudio2SubmixVoice IXAudio2SubmixVoice_iface;
+-
+- BOOL in_use;
+-
+- CRITICAL_SECTION lock;
+-
+- struct list entry;
+-} XA2SubmixImpl;
+-
+ static XA2SubmixImpl *impl_from_IXAudio2SubmixVoice(IXAudio2SubmixVoice *iface)
+ {
+ return CONTAINING_RECORD(iface, XA2SubmixImpl, IXAudio2SubmixVoice_iface);
+ }
+
+-struct _IXAudio2Impl {
+- IXAudio27 IXAudio27_iface;
+- IXAudio2 IXAudio2_iface;
+- IXAudio2MasteringVoice IXAudio2MasteringVoice_iface;
+-
+- LONG ref;
+-
+- CRITICAL_SECTION lock;
+-
+- HANDLE engine, mmevt;
+- BOOL stop_engine;
+-
+- DWORD version;
+-
+- struct list source_voices;
+- struct list submix_voices;
+-
+- IMMDeviceEnumerator *devenum;
+-
+- WCHAR **devids;
+- UINT32 ndevs;
+-
+- IAudioClient *aclient;
+- IAudioRenderClient *render;
+-
+- UINT32 period_frames;
+-
+- WAVEFORMATEXTENSIBLE fmt;
+-
+- ALCdevice *al_device;
+- ALCcontext *al_ctx;
+-
+- UINT32 ncbs;
+- IXAudio2EngineCallback **cbs;
+-
+- BOOL running;
+-};
+-
+ static inline IXAudio2Impl *impl_from_IXAudio2(IXAudio2 *iface)
+ {
+ return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2_iface);
+ }
+
+-static inline IXAudio2Impl *impl_from_IXAudio27(IXAudio27 *iface)
+-{
+- return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio27_iface);
+-}
+-
+ static IXAudio2Impl *impl_from_IXAudio2MasteringVoice(IXAudio2MasteringVoice *iface)
+ {
+ return CONTAINING_RECORD(iface, IXAudio2Impl, IXAudio2MasteringVoice_iface);
+@@ -890,254 +774,6 @@ static const IXAudio2SourceVoiceVtbl XAudio2SourceVoice_Vtbl = {
+ XA2SRC_SetSourceSampleRate
+ };
+
+-static void WINAPI XA27SRC_GetVoiceDetails(IXAudio27SourceVoice *iface,
+- XAUDIO2_VOICE_DETAILS *pVoiceDetails)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_GetVoiceDetails(&This->IXAudio2SourceVoice_iface, pVoiceDetails);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetOutputVoices(IXAudio27SourceVoice *iface,
+- const XAUDIO2_VOICE_SENDS *pSendList)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetOutputVoices(&This->IXAudio2SourceVoice_iface, pSendList);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetEffectChain(IXAudio27SourceVoice *iface,
+- const XAUDIO2_EFFECT_CHAIN *pEffectChain)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetEffectChain(&This->IXAudio2SourceVoice_iface, pEffectChain);
+-}
+-
+-static HRESULT WINAPI XA27SRC_EnableEffect(IXAudio27SourceVoice *iface,
+- UINT32 EffectIndex, UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_EnableEffect(&This->IXAudio2SourceVoice_iface, EffectIndex, OperationSet);
+-}
+-
+-static HRESULT WINAPI XA27SRC_DisableEffect(IXAudio27SourceVoice *iface,
+- UINT32 EffectIndex, UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_DisableEffect(&This->IXAudio2SourceVoice_iface, EffectIndex, OperationSet);
+-}
+-
+-static void WINAPI XA27SRC_GetEffectState(IXAudio27SourceVoice *iface,
+- UINT32 EffectIndex, BOOL *pEnabled)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- XA2SRC_GetEffectState(&This->IXAudio2SourceVoice_iface, EffectIndex, pEnabled);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetEffectParameters(IXAudio27SourceVoice *iface,
+- UINT32 EffectIndex, const void *pParameters, UINT32 ParametersByteSize,
+- UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetEffectParameters(&This->IXAudio2SourceVoice_iface,
+- EffectIndex, pParameters, ParametersByteSize, OperationSet);
+-}
+-
+-static HRESULT WINAPI XA27SRC_GetEffectParameters(IXAudio27SourceVoice *iface,
+- UINT32 EffectIndex, void *pParameters, UINT32 ParametersByteSize)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_GetEffectParameters(&This->IXAudio2SourceVoice_iface,
+- EffectIndex, pParameters, ParametersByteSize);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetFilterParameters(IXAudio27SourceVoice *iface,
+- const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetFilterParameters(&This->IXAudio2SourceVoice_iface,
+- pParameters, OperationSet);
+-}
+-
+-static void WINAPI XA27SRC_GetFilterParameters(IXAudio27SourceVoice *iface,
+- XAUDIO2_FILTER_PARAMETERS *pParameters)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- XA2SRC_GetFilterParameters(&This->IXAudio2SourceVoice_iface, pParameters);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetOutputFilterParameters(IXAudio27SourceVoice *iface,
+- IXAudio2Voice *pDestinationVoice,
+- const XAUDIO2_FILTER_PARAMETERS *pParameters, UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetOutputFilterParameters(&This->IXAudio2SourceVoice_iface,
+- pDestinationVoice, pParameters, OperationSet);
+-}
+-
+-static void WINAPI XA27SRC_GetOutputFilterParameters(IXAudio27SourceVoice *iface,
+- IXAudio2Voice *pDestinationVoice,
+- XAUDIO2_FILTER_PARAMETERS *pParameters)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- XA2SRC_GetOutputFilterParameters(&This->IXAudio2SourceVoice_iface,
+- pDestinationVoice, pParameters);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetVolume(IXAudio27SourceVoice *iface, float Volume,
+- UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetVolume(&This->IXAudio2SourceVoice_iface, Volume,
+- OperationSet);
+-}
+-
+-static void WINAPI XA27SRC_GetVolume(IXAudio27SourceVoice *iface, float *pVolume)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- XA2SRC_GetVolume(&This->IXAudio2SourceVoice_iface, pVolume);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetChannelVolumes(IXAudio27SourceVoice *iface,
+- UINT32 Channels, const float *pVolumes, UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetChannelVolumes(&This->IXAudio2SourceVoice_iface, Channels,
+- pVolumes, OperationSet);
+-}
+-
+-static void WINAPI XA27SRC_GetChannelVolumes(IXAudio27SourceVoice *iface,
+- UINT32 Channels, float *pVolumes)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- XA2SRC_GetChannelVolumes(&This->IXAudio2SourceVoice_iface, Channels,
+- pVolumes);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetOutputMatrix(IXAudio27SourceVoice *iface,
+- IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
+- UINT32 DestinationChannels, const float *pLevelMatrix,
+- UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetOutputMatrix(&This->IXAudio2SourceVoice_iface,
+- pDestinationVoice, SourceChannels, DestinationChannels,
+- pLevelMatrix, OperationSet);
+-}
+-
+-static void WINAPI XA27SRC_GetOutputMatrix(IXAudio27SourceVoice *iface,
+- IXAudio2Voice *pDestinationVoice, UINT32 SourceChannels,
+- UINT32 DestinationChannels, float *pLevelMatrix)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- XA2SRC_GetOutputMatrix(&This->IXAudio2SourceVoice_iface, pDestinationVoice,
+- SourceChannels, DestinationChannels, pLevelMatrix);
+-}
+-
+-static void WINAPI XA27SRC_DestroyVoice(IXAudio27SourceVoice *iface)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- XA2SRC_DestroyVoice(&This->IXAudio2SourceVoice_iface);
+-}
+-
+-static HRESULT WINAPI XA27SRC_Start(IXAudio27SourceVoice *iface, UINT32 Flags,
+- UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_Start(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
+-}
+-
+-static HRESULT WINAPI XA27SRC_Stop(IXAudio27SourceVoice *iface, UINT32 Flags,
+- UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_Stop(&This->IXAudio2SourceVoice_iface, Flags, OperationSet);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SubmitSourceBuffer(IXAudio27SourceVoice *iface,
+- const XAUDIO2_BUFFER *pBuffer, const XAUDIO2_BUFFER_WMA *pBufferWMA)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SubmitSourceBuffer(&This->IXAudio2SourceVoice_iface, pBuffer,
+- pBufferWMA);
+-}
+-
+-static HRESULT WINAPI XA27SRC_FlushSourceBuffers(IXAudio27SourceVoice *iface)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_FlushSourceBuffers(&This->IXAudio2SourceVoice_iface);
+-}
+-
+-static HRESULT WINAPI XA27SRC_Discontinuity(IXAudio27SourceVoice *iface)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_Discontinuity(&This->IXAudio2SourceVoice_iface);
+-}
+-
+-static HRESULT WINAPI XA27SRC_ExitLoop(IXAudio27SourceVoice *iface, UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_ExitLoop(&This->IXAudio2SourceVoice_iface, OperationSet);
+-}
+-
+-static void WINAPI XA27SRC_GetState(IXAudio27SourceVoice *iface,
+- XAUDIO2_VOICE_STATE *pVoiceState)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_GetState(&This->IXAudio2SourceVoice_iface, pVoiceState, 0);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetFrequencyRatio(IXAudio27SourceVoice *iface,
+- float Ratio, UINT32 OperationSet)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetFrequencyRatio(&This->IXAudio2SourceVoice_iface, Ratio, OperationSet);
+-}
+-
+-static void WINAPI XA27SRC_GetFrequencyRatio(IXAudio27SourceVoice *iface, float *pRatio)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_GetFrequencyRatio(&This->IXAudio2SourceVoice_iface, pRatio);
+-}
+-
+-static HRESULT WINAPI XA27SRC_SetSourceSampleRate(
+- IXAudio27SourceVoice *iface,
+- UINT32 NewSourceSampleRate)
+-{
+- XA2SourceImpl *This = impl_from_IXAudio27SourceVoice(iface);
+- return XA2SRC_SetSourceSampleRate(&This->IXAudio2SourceVoice_iface, NewSourceSampleRate);
+-}
+-
+-static const IXAudio27SourceVoiceVtbl XAudio27SourceVoice_Vtbl = {
+- XA27SRC_GetVoiceDetails,
+- XA27SRC_SetOutputVoices,
+- XA27SRC_SetEffectChain,
+- XA27SRC_EnableEffect,
+- XA27SRC_DisableEffect,
+- XA27SRC_GetEffectState,
+- XA27SRC_SetEffectParameters,
+- XA27SRC_GetEffectParameters,
+- XA27SRC_SetFilterParameters,
+- XA27SRC_GetFilterParameters,
+- XA27SRC_SetOutputFilterParameters,
+- XA27SRC_GetOutputFilterParameters,
+- XA27SRC_SetVolume,
+- XA27SRC_GetVolume,
+- XA27SRC_SetChannelVolumes,
+- XA27SRC_GetChannelVolumes,
+- XA27SRC_SetOutputMatrix,
+- XA27SRC_GetOutputMatrix,
+- XA27SRC_DestroyVoice,
+- XA27SRC_Start,
+- XA27SRC_Stop,
+- XA27SRC_SubmitSourceBuffer,
+- XA27SRC_FlushSourceBuffers,
+- XA27SRC_Discontinuity,
+- XA27SRC_ExitLoop,
+- XA27SRC_GetState,
+- XA27SRC_SetFrequencyRatio,
+- XA27SRC_GetFrequencyRatio,
+- XA27SRC_SetSourceSampleRate
+-};
+-
+ static void WINAPI XA2M_GetVoiceDetails(IXAudio2MasteringVoice *iface,
+ XAUDIO2_VOICE_DETAILS *pVoiceDetails)
+ {
+@@ -1712,6 +1348,7 @@ static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
+
+ list_add_head(&This->source_voices, &src->entry);
+
++ src->IXAudio23SourceVoice_iface.lpVtbl = &XAudio23SourceVoice_Vtbl;
+ src->IXAudio27SourceVoice_iface.lpVtbl = &XAudio27SourceVoice_Vtbl;
+ src->IXAudio2SourceVoice_iface.lpVtbl = &XAudio2SourceVoice_Vtbl;
+
+@@ -1750,7 +1387,9 @@ static HRESULT WINAPI IXAudio2Impl_CreateSourceVoice(IXAudio2 *iface,
+
+ alSourcePlay(src->al_src);
+
+- if(This->version == 27)
++ if(This->version <= 23)
++ *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio23SourceVoice_iface;
++ else if(This->version <= 27)
+ *ppSourceVoice = (IXAudio2SourceVoice*)&src->IXAudio27SourceVoice_iface;
+ else
+ *ppSourceVoice = &src->IXAudio2SourceVoice_iface;
+@@ -1789,6 +1428,7 @@ static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
+
+ list_add_head(&This->submix_voices, &sub->entry);
+
++ sub->IXAudio23SubmixVoice_iface.lpVtbl = &XAudio23SubmixVoice_Vtbl;
+ sub->IXAudio2SubmixVoice_iface.lpVtbl = &XAudio2SubmixVoice_Vtbl;
+
+ InitializeCriticalSection(&sub->lock);
+@@ -1799,7 +1439,10 @@ static HRESULT WINAPI IXAudio2Impl_CreateSubmixVoice(IXAudio2 *iface,
+
+ LeaveCriticalSection(&This->lock);
+
+- *ppSubmixVoice = &sub->IXAudio2SubmixVoice_iface;
++ if(This->version <= 23)
++ *ppSubmixVoice = (IXAudio2SubmixVoice*)&sub->IXAudio23SubmixVoice_iface;
++ else
++ *ppSubmixVoice = &sub->IXAudio2SubmixVoice_iface;
+
+ TRACE("Created submix voice: %p\n", sub);
+
+@@ -2022,7 +1665,10 @@ static HRESULT WINAPI IXAudio2Impl_CreateMasteringVoice(IXAudio2 *iface,
+
+ IAudioClient_Start(This->aclient);
+
+- *ppMasteringVoice = &This->IXAudio2MasteringVoice_iface;
++ if(This->version <= 23)
++ *ppMasteringVoice = (IXAudio2MasteringVoice*)&This->IXAudio23MasteringVoice_iface;
++ else
++ *ppMasteringVoice = &This->IXAudio2MasteringVoice_iface;
+
+ exit:
+ if(FAILED(hr)){
+@@ -2121,235 +1767,6 @@ static const IXAudio2Vtbl XAudio2_Vtbl =
+ IXAudio2Impl_SetDebugConfiguration
+ };
+
+-static HRESULT WINAPI XA27_QueryInterface(IXAudio27 *iface, REFIID riid,
+- void **ppvObject)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_QueryInterface(&This->IXAudio2_iface, riid, ppvObject);
+-}
+-
+-static ULONG WINAPI XA27_AddRef(IXAudio27 *iface)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_AddRef(&This->IXAudio2_iface);
+-}
+-
+-static ULONG WINAPI XA27_Release(IXAudio27 *iface)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_Release(&This->IXAudio2_iface);
+-}
+-
+-static HRESULT WINAPI XA27_GetDeviceCount(IXAudio27 *iface, UINT32 *pCount)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+-
+- TRACE("%p, %p\n", This, pCount);
+-
+- *pCount = This->ndevs;
+-
+- return S_OK;
+-}
+-
+-static HRESULT WINAPI XA27_GetDeviceDetails(IXAudio27 *iface, UINT32 index,
+- XAUDIO2_DEVICE_DETAILS *pDeviceDetails)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- HRESULT hr;
+- IMMDevice *dev;
+- IAudioClient *client;
+- IPropertyStore *ps;
+- WAVEFORMATEX *wfx;
+- PROPVARIANT var;
+-
+- TRACE("%p, %u, %p\n", This, index, pDeviceDetails);
+-
+- if(index >= This->ndevs)
+- return E_INVALIDARG;
+-
+- hr = IMMDeviceEnumerator_GetDevice(This->devenum, This->devids[index], &dev);
+- if(FAILED(hr)){
+- WARN("GetDevice failed: %08x\n", hr);
+- return hr;
+- }
+-
+- hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER,
+- NULL, (void**)&client);
+- if(FAILED(hr)){
+- WARN("Activate failed: %08x\n", hr);
+- IMMDevice_Release(dev);
+- return hr;
+- }
+-
+- hr = IMMDevice_OpenPropertyStore(dev, STGM_READ, &ps);
+- if(FAILED(hr)){
+- WARN("OpenPropertyStore failed: %08x\n", hr);
+- IAudioClient_Release(client);
+- IMMDevice_Release(dev);
+- return hr;
+- }
+-
+- PropVariantInit(&var);
+-
+- hr = IPropertyStore_GetValue(ps, (PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &var);
+- if(FAILED(hr)){
+- WARN("GetValue failed: %08x\n", hr);
+- goto done;
+- }
+-
+- lstrcpynW(pDeviceDetails->DisplayName, var.u.pwszVal, sizeof(pDeviceDetails->DisplayName)/sizeof(WCHAR));
+-
+- PropVariantClear(&var);
+-
+- hr = IAudioClient_GetMixFormat(client, &wfx);
+- if(FAILED(hr)){
+- WARN("GetMixFormat failed: %08x\n", hr);
+- goto done;
+- }
+-
+- lstrcpyW(pDeviceDetails->DeviceID, This->devids[index]);
+-
+- if(index == 0)
+- pDeviceDetails->Role = GlobalDefaultDevice;
+- else
+- pDeviceDetails->Role = NotDefaultDevice;
+-
+- if(sizeof(WAVEFORMATEX) + wfx->cbSize > sizeof(pDeviceDetails->OutputFormat)){
+- FIXME("AudioClient format is too large to fit into WAVEFORMATEXTENSIBLE!\n");
+- CoTaskMemFree(wfx);
+- hr = E_FAIL;
+- goto done;
+- }
+- memcpy(&pDeviceDetails->OutputFormat, wfx, sizeof(WAVEFORMATEX) + wfx->cbSize);
+-
+- CoTaskMemFree(wfx);
+-
+-done:
+- IPropertyStore_Release(ps);
+- IAudioClient_Release(client);
+- IMMDevice_Release(dev);
+-
+- return hr;
+-}
+-
+-static HRESULT WINAPI XA27_Initialize(IXAudio27 *iface, UINT32 flags,
+- XAUDIO2_PROCESSOR processor)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- TRACE("(%p)->(0x%x, 0x%x)\n", This, flags, processor);
+- return S_OK;
+-}
+-
+-static HRESULT WINAPI XA27_RegisterForCallbacks(IXAudio27 *iface,
+- IXAudio2EngineCallback *pCallback)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_RegisterForCallbacks(&This->IXAudio2_iface, pCallback);
+-}
+-
+-static void WINAPI XA27_UnregisterForCallbacks(IXAudio27 *iface,
+- IXAudio2EngineCallback *pCallback)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- IXAudio2Impl_UnregisterForCallbacks(&This->IXAudio2_iface, pCallback);
+-}
+-
+-static HRESULT WINAPI XA27_CreateSourceVoice(IXAudio27 *iface,
+- IXAudio2SourceVoice **ppSourceVoice, const WAVEFORMATEX *pSourceFormat,
+- UINT32 flags, float maxFrequencyRatio,
+- IXAudio2VoiceCallback *pCallback, const XAUDIO2_VOICE_SENDS *pSendList,
+- const XAUDIO2_EFFECT_CHAIN *pEffectChain)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_CreateSourceVoice(&This->IXAudio2_iface, ppSourceVoice,
+- pSourceFormat, flags, maxFrequencyRatio, pCallback, pSendList,
+- pEffectChain);
+-}
+-
+-static HRESULT WINAPI XA27_CreateSubmixVoice(IXAudio27 *iface,
+- IXAudio2SubmixVoice **ppSubmixVoice, UINT32 inputChannels,
+- UINT32 inputSampleRate, UINT32 flags, UINT32 processingStage,
+- const XAUDIO2_VOICE_SENDS *pSendList,
+- const XAUDIO2_EFFECT_CHAIN *pEffectChain)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_CreateSubmixVoice(&This->IXAudio2_iface, ppSubmixVoice,
+- inputChannels, inputSampleRate, flags, processingStage, pSendList,
+- pEffectChain);
+-}
+-
+-static HRESULT WINAPI XA27_CreateMasteringVoice(IXAudio27 *iface,
+- IXAudio2MasteringVoice **ppMasteringVoice, UINT32 inputChannels,
+- UINT32 inputSampleRate, UINT32 flags, UINT32 deviceIndex,
+- const XAUDIO2_EFFECT_CHAIN *pEffectChain)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+-
+- TRACE("(%p)->(%p, %u, %u, 0x%x, %u, %p)\n", This, ppMasteringVoice,
+- inputChannels, inputSampleRate, flags, deviceIndex,
+- pEffectChain);
+-
+- if(deviceIndex >= This->ndevs)
+- return E_INVALIDARG;
+-
+- return IXAudio2Impl_CreateMasteringVoice(&This->IXAudio2_iface, ppMasteringVoice,
+- inputChannels, inputSampleRate, flags, This->devids[deviceIndex],
+- pEffectChain, AudioCategory_GameEffects);
+-}
+-
+-static HRESULT WINAPI XA27_StartEngine(IXAudio27 *iface)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_StartEngine(&This->IXAudio2_iface);
+-}
+-
+-static void WINAPI XA27_StopEngine(IXAudio27 *iface)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_StopEngine(&This->IXAudio2_iface);
+-}
+-
+-static HRESULT WINAPI XA27_CommitChanges(IXAudio27 *iface, UINT32 operationSet)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_CommitChanges(&This->IXAudio2_iface, operationSet);
+-}
+-
+-static void WINAPI XA27_GetPerformanceData(IXAudio27 *iface,
+- XAUDIO2_PERFORMANCE_DATA *pPerfData)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_GetPerformanceData(&This->IXAudio2_iface, pPerfData);
+-}
+-
+-static void WINAPI XA27_SetDebugConfiguration(IXAudio27 *iface,
+- const XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
+- void *pReserved)
+-{
+- IXAudio2Impl *This = impl_from_IXAudio27(iface);
+- return IXAudio2Impl_SetDebugConfiguration(&This->IXAudio2_iface,
+- pDebugConfiguration, pReserved);
+-}
+-
+-static const IXAudio27Vtbl XAudio27_Vtbl = {
+- XA27_QueryInterface,
+- XA27_AddRef,
+- XA27_Release,
+- XA27_GetDeviceCount,
+- XA27_GetDeviceDetails,
+- XA27_Initialize,
+- XA27_RegisterForCallbacks,
+- XA27_UnregisterForCallbacks,
+- XA27_CreateSourceVoice,
+- XA27_CreateSubmixVoice,
+- XA27_CreateMasteringVoice,
+- XA27_StartEngine,
+- XA27_StopEngine,
+- XA27_CommitChanges,
+- XA27_GetPerformanceData,
+- XA27_SetDebugConfiguration
+-};
+-
+ typedef struct _VUMeterImpl {
+ IXAPO IXAPO_iface;
+ IXAPOParameters IXAPOParameters_iface;
+@@ -2752,6 +2169,17 @@ static const IXAPOParametersVtbl RVBXAPOParameters_Vtbl = {
+ RVBXAPOParams_GetParameters
+ };
+
++struct xaudio2_cf {
++ IClassFactory IClassFactory_iface;
++ LONG ref;
++ DWORD version;
++};
++
++struct xaudio2_cf *impl_from_IClassFactory(IClassFactory *iface)
++{
++ return CONTAINING_RECORD(iface, struct xaudio2_cf, IClassFactory_iface);
++}
++
+ static HRESULT WINAPI XAudio2CF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
+ {
+ if(IsEqualGUID(riid, &IID_IUnknown)
+@@ -2769,12 +2197,20 @@ static HRESULT WINAPI XAudio2CF_QueryInterface(IClassFactory *iface, REFIID riid
+
+ static ULONG WINAPI XAudio2CF_AddRef(IClassFactory *iface)
+ {
+- return 2;
++ struct xaudio2_cf *This = impl_from_IClassFactory(iface);
++ ULONG ref = InterlockedIncrement(&This->ref);
++ TRACE("(%p)->(): Refcount now %u\n", This, ref);
++ return ref;
+ }
+
+ static ULONG WINAPI XAudio2CF_Release(IClassFactory *iface)
+ {
+- return 1;
++ struct xaudio2_cf *This = impl_from_IClassFactory(iface);
++ ULONG ref = InterlockedDecrement(&This->ref);
++ TRACE("(%p)->(): Refcount now %u\n", This, ref);
++ if (!ref)
++ HeapFree(GetProcessHeap(), 0, This);
++ return ref;
+ }
+
+ static HRESULT initialize_mmdevices(IXAudio2Impl *This)
+@@ -2853,10 +2289,11 @@ static HRESULT initialize_mmdevices(IXAudio2Impl *This)
+ static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
+ REFIID riid, void **ppobj)
+ {
++ struct xaudio2_cf *This = impl_from_IClassFactory(iface);
+ HRESULT hr;
+ IXAudio2Impl *object;
+
+- TRACE("(static)->(%p,%s,%p)\n", pOuter, debugstr_guid(riid), ppobj);
++ TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
+
+ *ppobj = NULL;
+
+@@ -2869,11 +2306,12 @@ static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *p
+
+ object->IXAudio27_iface.lpVtbl = &XAudio27_Vtbl;
+ object->IXAudio2_iface.lpVtbl = &XAudio2_Vtbl;
++ object->IXAudio23MasteringVoice_iface.lpVtbl = &XAudio23MasteringVoice_Vtbl;
+ object->IXAudio2MasteringVoice_iface.lpVtbl = &XAudio2MasteringVoice_Vtbl;
+
+ if(IsEqualGUID(riid, &IID_IXAudio27))
+- object->version = 27;
+- else
++ object->version = This->version;
++ else /* only xaudio 2.8 has a different IID */
+ object->version = 28;
+
+ list_init(&object->source_voices);
+@@ -2903,6 +2341,16 @@ static HRESULT WINAPI XAudio2CF_CreateInstance(IClassFactory *iface, IUnknown *p
+ return hr;
+ }
+
++static ULONG WINAPI static_AddRef(IClassFactory *iface)
++{
++ return 2;
++}
++
++static ULONG WINAPI static_Release(IClassFactory *iface)
++{
++ return 1;
++}
++
+ static HRESULT WINAPI VUMeterCF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
+ REFIID riid, void **ppobj)
+ {
+@@ -2979,8 +2427,8 @@ static const IClassFactoryVtbl XAudio2CF_Vtbl =
+ static const IClassFactoryVtbl VUMeterCF_Vtbl =
+ {
+ XAudio2CF_QueryInterface,
+- XAudio2CF_AddRef,
+- XAudio2CF_Release,
++ static_AddRef,
++ static_Release,
+ VUMeterCF_CreateInstance,
+ XAudio2CF_LockServer
+ };
+@@ -2988,24 +2436,40 @@ static const IClassFactoryVtbl VUMeterCF_Vtbl =
+ static const IClassFactoryVtbl ReverbCF_Vtbl =
+ {
+ XAudio2CF_QueryInterface,
+- XAudio2CF_AddRef,
+- XAudio2CF_Release,
++ static_AddRef,
++ static_Release,
+ ReverbCF_CreateInstance,
+ XAudio2CF_LockServer
+ };
+
+-static IClassFactory xaudio2_cf = { &XAudio2CF_Vtbl };
+ static IClassFactory vumeter_cf = { &VUMeterCF_Vtbl };
+ static IClassFactory reverb_cf = { &ReverbCF_Vtbl };
+
++static IClassFactory *make_xaudio2_factory(DWORD version)
++{
++ struct xaudio2_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xaudio2_cf));
++ ret->IClassFactory_iface.lpVtbl = &XAudio2CF_Vtbl;
++ ret->version = version;
++ ret->ref = 0;
++ return &ret->IClassFactory_iface;
++}
++
+ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
+ {
+ IClassFactory *factory = NULL;
+
+ TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+
+- if(IsEqualGUID(rclsid, &CLSID_XAudio2)) {
+- factory = &xaudio2_cf;
++ if IsEqualGUID(rclsid, &CLSID_XAudio23){
++ factory = make_xaudio2_factory(23);
++ }else if(IsEqualGUID(rclsid, &CLSID_XAudio24)){
++ factory = make_xaudio2_factory(24);
++ }else if(IsEqualGUID(rclsid, &CLSID_XAudio25)){
++ factory = make_xaudio2_factory(25);
++ }else if(IsEqualGUID(rclsid, &CLSID_XAudio26)){
++ factory = make_xaudio2_factory(26);
++ }else if(IsEqualGUID(rclsid, &CLSID_XAudio2)){
++ factory = make_xaudio2_factory(27);
+ }else if(IsEqualGUID(rclsid, &CLSID_AudioVolumeMeter)) {
+ factory = &vumeter_cf;
+ }else if(IsEqualGUID(rclsid, &CLSID_AudioReverb)) {
+diff --git a/dlls/xaudio2_7/xaudio_private.h b/dlls/xaudio2_7/xaudio_private.h
+new file mode 100644
+index 0000000..5a0fcdf
+--- /dev/null
++++ b/dlls/xaudio2_7/xaudio_private.h
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (c) 2015 Andrew Eikum for CodeWeavers
++ *
++ * 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 "windef.h"
++#include "winbase.h"
++#include "winuser.h"
++#include "wine/list.h"
++
++#include "mmsystem.h"
++#include "xaudio2.h"
++#include "xaudio2fx.h"
++#include "xapo.h"
++#include "devpkey.h"
++#include "mmdeviceapi.h"
++#include "audioclient.h"
++
++#include <AL/al.h>
++#include <AL/alc.h>
++#include <AL/alext.h>
++
++typedef struct _XA2Buffer {
++ XAUDIO2_BUFFER xa2buffer;
++ DWORD offs_bytes;
++ UINT32 latest_al_buf, looped, loop_end_bytes, play_end_bytes, cur_end_bytes;
++} XA2Buffer;
++
++typedef struct _IXAudio2Impl IXAudio2Impl;
++
++typedef struct _XA2SourceImpl {
++ IXAudio23SourceVoice IXAudio23SourceVoice_iface;
++ IXAudio27SourceVoice IXAudio27SourceVoice_iface;
++ IXAudio2SourceVoice IXAudio2SourceVoice_iface;
++
++ IXAudio2Impl *xa2;
++
++ BOOL in_use;
++
++ CRITICAL_SECTION lock;
++
++ WAVEFORMATEX *fmt;
++ ALenum al_fmt;
++ UINT32 submit_blocksize;
++
++ IXAudio2VoiceCallback *cb;
++
++ DWORD nsends;
++ XAUDIO2_SEND_DESCRIPTOR *sends;
++
++ BOOL running;
++
++ UINT64 played_frames;
++
++ XA2Buffer buffers[XAUDIO2_MAX_QUEUED_BUFFERS];
++ UINT32 first_buf, cur_buf, nbufs, in_al_bytes;
++
++ UINT32 scratch_bytes, convert_bytes;
++ BYTE *scratch_buf, *convert_buf;
++
++ ALuint al_src;
++ /* most cases will only need about 4 AL buffers, but some corner cases
++ * could require up to MAX_QUEUED_BUFFERS */
++ ALuint al_bufs[XAUDIO2_MAX_QUEUED_BUFFERS];
++ DWORD first_al_buf, al_bufs_used;
++
++ struct list entry;
++} XA2SourceImpl;
++
++typedef struct _XA2SubmixImpl {
++ IXAudio23SubmixVoice IXAudio23SubmixVoice_iface;
++ IXAudio2SubmixVoice IXAudio2SubmixVoice_iface;
++
++ BOOL in_use;
++
++ CRITICAL_SECTION lock;
++
++ struct list entry;
++} XA2SubmixImpl;
++
++struct _IXAudio2Impl {
++ IXAudio27 IXAudio27_iface;
++ IXAudio2 IXAudio2_iface;
++ IXAudio23MasteringVoice IXAudio23MasteringVoice_iface;
++ IXAudio2MasteringVoice IXAudio2MasteringVoice_iface;
++
++ LONG ref;
++
++ CRITICAL_SECTION lock;
++
++ HANDLE engine, mmevt;
++ BOOL stop_engine;
++
++ DWORD version;
++
++ struct list source_voices;
++ struct list submix_voices;
++
++ IMMDeviceEnumerator *devenum;
++
++ WCHAR **devids;
++ UINT32 ndevs;
++
++ IAudioClient *aclient;
++ IAudioRenderClient *render;
++
++ UINT32 period_frames;
++
++ WAVEFORMATEXTENSIBLE fmt;
++
++ ALCdevice *al_device;
++ ALCcontext *al_ctx;
++
++ UINT32 ncbs;
++ IXAudio2EngineCallback **cbs;
++
++ BOOL running;
++};
++
++extern const IXAudio27SourceVoiceVtbl XAudio27SourceVoice_Vtbl DECLSPEC_HIDDEN;
++extern const IXAudio27Vtbl XAudio27_Vtbl DECLSPEC_HIDDEN;
++
++extern const IXAudio23SourceVoiceVtbl XAudio23SourceVoice_Vtbl DECLSPEC_HIDDEN;
++extern const IXAudio23SubmixVoiceVtbl XAudio23SubmixVoice_Vtbl DECLSPEC_HIDDEN;
++extern const IXAudio23MasteringVoiceVtbl XAudio23MasteringVoice_Vtbl DECLSPEC_HIDDEN;
+diff --git a/include/commctrl.h b/include/commctrl.h
+index 0bcaeb6..5029e77 100644
+--- a/include/commctrl.h
++++ b/include/commctrl.h
+@@ -42,7 +42,14 @@ BOOL WINAPI InitCommonControlsEx (const INITCOMMONCONTROLSEX*);
+ LANGID WINAPI GetMUILanguage (VOID);
+ VOID WINAPI InitMUILanguage (LANGID uiLang);
+
+-HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE, PCWSTR, int, int, HICON *);
++enum _LI_METRIC
++{
++ LIM_SMALL,
++ LIM_LARGE
++};
++
++HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE, const WCHAR *, int, int, HICON *);
++HRESULT WINAPI LoadIconMetric(HINSTANCE, const WCHAR *, int, HICON *);
+
+ #define COMCTL32_VERSION 5 /* dll version */
+
+diff --git a/include/wine/d3dadapter.h b/include/wine/d3dadapter.h
+new file mode 100644
+index 0000000..6f90338
+--- /dev/null
++++ b/include/wine/d3dadapter.h
+@@ -0,0 +1,42 @@
++/*
++ * d3dadapter display driver definitions
++ *
++ * Copyright (c) 2013 Joakim Sindholt
++ *
++ * 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_D3DADAPTER_H
++#define __WINE_D3DADAPTER_H
++
++#ifndef __WINE_CONFIG_H
++# error You must include config.h to use this header
++#endif
++
++#ifdef SONAME_D3DADAPTER9
++
++#include <d3dadapter/d3dadapter9.h>
++
++#define WINE_D3DADAPTER_DRIVER_VERSION 0
++
++struct d3dadapter_funcs
++{
++ HRESULT (*create_present_group)(const WCHAR *device_name, UINT adapter, HWND focus, D3DPRESENT_PARAMETERS *params, unsigned nparams, ID3DPresentGroup **group);
++ HRESULT (*create_adapter9)(HDC hdc, ID3DAdapter9 **adapter);
++};
++
++#endif /* SONAME_D3DADAPTER9 */
++
++#endif /* __WINE_D3DADAPTER_H */
+diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h
+index 6f67653..d8706d8 100644
+--- a/include/wine/gdi_driver.h
++++ b/include/wine/gdi_driver.h
+@@ -25,6 +25,7 @@
+
+ struct gdi_dc_funcs;
+ struct opengl_funcs;
++struct d3dadapter_funcs;
+
+ typedef struct gdi_physdev
+ {
+@@ -191,6 +192,7 @@ struct gdi_dc_funcs
+ BOOL (*pUnrealizePalette)(HPALETTE);
+ BOOL (*pWidenPath)(PHYSDEV);
+ struct opengl_funcs * (*wine_get_wgl_driver)(PHYSDEV,UINT);
++ struct d3dadapter_funcs * (*wine_get_d3dadapter_driver)(PHYSDEV,UINT);
+
+ /* priority order for the driver on the stack */
+ UINT priority;
+@@ -278,5 +280,6 @@ extern void CDECL __wine_set_visible_region( HDC hdc, HRGN hrgn, const RECT *vis
+ const RECT *device_rect, struct window_surface *surface );
+ extern void CDECL __wine_set_display_driver( HMODULE module );
+ extern struct opengl_funcs * CDECL __wine_get_wgl_driver( HDC hdc, UINT version );
++extern struct d3dadapter_funcs * CDECL __wine_get_d3dadapter_driver( HDC hdc, UINT version );
+
+ #endif /* __WINE_WINE_GDI_DRIVER_H */
+diff --git a/include/xaudio2.idl b/include/xaudio2.idl
+index 3ac3e22..5de6622 100644
+--- a/include/xaudio2.idl
++++ b/include/xaudio2.idl
+@@ -31,6 +31,34 @@ coclass XAudio2 {
+ }
+
+ [
++ uuid(4c5e637a-16c7-4de3-9c46-5ed22181962d)
++]
++coclass XAudio23 {
++ interface IUnknown;
++}
++
++[
++ uuid(03219e78-5bc3-44d1-b92e-f63d89cc6526)
++]
++coclass XAudio24 {
++ interface IUnknown;
++}
++
++[
++ uuid(4c9b6dde-6809-46e6-a278-9b6a97588670)
++]
++coclass XAudio25 {
++ interface IUnknown;
++}
++
++[
++ uuid(3eda9b49-2085-498b-9bb2-39a6778493de)
++]
++coclass XAudio26 {
++ interface IUnknown;
++}
++
++[
+ uuid(db05ea35-0329-4d4b-a53a-6dead03d3852)
+ ]
+ coclass XAudio2Debug {
+@@ -153,6 +181,13 @@ typedef struct XAUDIO2_SEND_DESCRIPTOR
+ IXAudio2Voice* pOutputVoice;
+ } XAUDIO2_SEND_DESCRIPTOR;
+
++/* XAudio2 2.3's XAUDIO2_VOICE_SENDS struct */
++typedef struct XAUDIO23_VOICE_SENDS
++{
++ UINT32 OutputCount;
++ IXAudio2Voice **pOutputVoices;
++} XAUDIO23_VOICE_SENDS;
++
+ typedef struct XAUDIO2_VOICE_SENDS
+ {
+ UINT32 SendCount;
+@@ -222,6 +257,80 @@ typedef struct XAUDIO2_FILTER_PARAMETERS
+ float OneOverQ;
+ } XAUDIO2_FILTER_PARAMETERS;
+
++/* XAudio 2.3's IXAudio2Voice */
++/* XAudio2 2.3's IXAudio2Voice interface. Actually called
++ * IXAudio2Voice in the Nov 2008 DX SDK */
++[
++ object,
++ local
++]
++interface IXAudio23Voice
++{
++ void GetVoiceDetails([out] XAUDIO2_VOICE_DETAILS* pVoiceDetails);
++
++ HRESULT SetOutputVoices([in] const XAUDIO23_VOICE_SENDS* pSendList);
++
++ HRESULT SetEffectChain([in] const XAUDIO2_EFFECT_CHAIN* pEffectChain);
++
++ HRESULT EnableEffect(
++ [in] UINT32 EffectIndex,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ HRESULT DisableEffect(
++ [in] UINT32 EffectIndex,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ void GetEffectState(
++ [in] UINT32 EffectIndex,
++ [out] BOOL* pEnabled);
++
++ HRESULT SetEffectParameters(
++ [in] UINT32 EffectIndex,
++ [in] const void* pParameters,
++ [in] UINT32 ParametersByteSize,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ HRESULT GetEffectParameters(
++ [in] UINT32 EffectIndex,
++ [out] void* pParameters,
++ [in] UINT32 ParametersByteSize);
++
++ HRESULT SetFilterParameters(
++ [in] const XAUDIO2_FILTER_PARAMETERS* pParameters,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ void GetFilterParameters([out] XAUDIO2_FILTER_PARAMETERS* pParameters);
++
++ HRESULT SetVolume(
++ [in] float Volume,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ void GetVolume([out] float* pVolume);
++
++ HRESULT SetChannelVolumes(
++ [in] UINT32 Channels,
++ [in, size_is(Channels)] const float* pVolumes,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ void GetChannelVolumes(
++ [in] UINT32 Channels,
++ [out, size_is(Channels)] float* pVolumes);
++
++ HRESULT SetOutputMatrix(
++ [in] IXAudio2Voice* pDestinationVoice,
++ [in] UINT32 SourceChannels,
++ [in] UINT32 DestinationChannels,
++ [in, size_is(SourceChannels * DestinationChannels)] const float* pLevelMatrix,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ void GetOutputMatrix(
++ [in] IXAudio2Voice* pDestinationVoice,
++ [in] UINT32 SourceChannels,
++ [in] UINT32 DestinationChannels,
++ [out, size_is(SourceChannels * DestinationChannels)] float* pLevelMatrix);
++
++ void DestroyVoice();
++}
+ [
+ object,
+ local
+@@ -332,6 +441,40 @@ typedef struct XAUDIO2_VOICE_STATE
+ [
+ local
+ ]
++/* XAudio2 2.3's IXAudio2SourceVoice interface. Actually called
++ * IXAudio2SourceVoice in the Nov 2008 DX SDK */
++interface IXAudio23SourceVoice : IXAudio23Voice
++{
++ HRESULT Start(
++ [in, defaultvalue(0)] UINT32 Flags,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ HRESULT Stop(
++ [in, defaultvalue(0)] UINT32 Flags,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ HRESULT SubmitSourceBuffer(
++ [in] const XAUDIO2_BUFFER* pBuffer,
++ [in, defaultvalue(NULL)] const XAUDIO2_BUFFER_WMA* pBufferWMA);
++
++ HRESULT FlushSourceBuffers();
++
++ HRESULT Discontinuity();
++
++ HRESULT ExitLoop([in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ void GetState([out] XAUDIO2_VOICE_STATE* pVoiceState);
++
++ HRESULT SetFrequencyRatio(
++ [in] float Ratio,
++ [in, defaultvalue(XAUDIO2_COMMIT_NOW)] UINT32 OperationSet);
++
++ void GetFrequencyRatio([out] float* pRatio);
++}
++
++[
++ local
++]
+ /* XAudio2 2.7's IXAudio2SourceVoice interface. Actually called
+ * IXAudio2SourceVoice in the Jun 2010 DX SDK */
+ interface IXAudio27SourceVoice : IXAudio2Voice
+@@ -403,6 +546,15 @@ interface IXAudio2SourceVoice : IXAudio2Voice
+ [
+ local
+ ]
++/* XAudio2 2.3's IXAudio2SubmixVoice interface. Actually called
++ * IXAudio2SubmixVoice in the Nov 2008 DX SDK */
++interface IXAudio23SubmixVoice : IXAudio23Voice
++{
++}
++
++[
++ local
++]
+ interface IXAudio2SubmixVoice : IXAudio2Voice
+ {
+ }
+@@ -410,6 +562,15 @@ interface IXAudio2SubmixVoice : IXAudio2Voice
+ [
+ local
+ ]
++/* XAudio2 2.3's IXAudio2MasteringVoice interface. Actually called
++ * IXAudio2MasteringVoice in the Nov 2008 DX SDK */
++interface IXAudio23MasteringVoice : IXAudio23Voice
++{
++}
++
++[
++ local
++]
+ interface IXAudio2MasteringVoice : IXAudio2Voice
+ {
+ /* not present in XAudio2 2.7 */
+diff --git a/po/fr.po b/po/fr.po
+index 0918427..f1a9401 100644
+--- a/po/fr.po
++++ b/po/fr.po
+@@ -5,7 +5,7 @@ msgstr ""
+ "Project-Id-Version: Wine\n"
+ "Report-Msgid-Bugs-To: http://bugs.winehq.org\n"
+ "POT-Creation-Date: N/A\n"
+-"PO-Revision-Date: 2015-07-18 09:12+0100\n"
++"PO-Revision-Date: 2015-10-03 11:45+0100\n"
+ "Last-Translator: Frédéric Delanoy <frederic.delanoy@gmail.com>\n"
+ "Language-Team: French\n"
+ "Language: fr\n"
+@@ -7496,16 +7496,12 @@ msgid "&Convert..."
+ msgstr "&Convertir..."
+
+ #: oledlg.rc:36
+-#, fuzzy
+-#| msgid "&Object"
+ msgid "%1 %2 &Object"
+-msgstr "&Objet"
++msgstr "&Objet %1 %2"
+
+ #: oledlg.rc:34
+-#, fuzzy
+-#| msgid "&Object"
+ msgid "%1 &Object"
+-msgstr "&Objet"
++msgstr "&Objet %1"
+
+ #: oledlg.rc:33 oleview.rc:40
+ msgid "&Object"
+@@ -9310,11 +9306,11 @@ msgstr "Volume"
+
+ #: winmm.rc:138
+ msgid "Master Volume"
+-msgstr ""
++msgstr "Volume principal"
+
+ #: winmm.rc:139
+ msgid "Mute"
+-msgstr ""
++msgstr "Muet"
+
+ #: winspool.rc:37
+ msgid "Print to File"
+@@ -13010,18 +13006,18 @@ msgstr ""
+
+ #: uninstaller.rc:31
+ msgid "uninstaller: The application with GUID '%1' was not found\n"
+-msgstr ""
++msgstr "uninstaller : l'application de GUID « %1 » est introuvable\n"
+
+ #: uninstaller.rc:32
+ msgid ""
+ "uninstaller: The option '--remove' must be followed by an application GUID\n"
+ msgstr ""
++"uninstaller : l'option « --remove » doit être suivie d'un GUID "
++"d'application\n"
+
+ #: uninstaller.rc:33
+-#, fuzzy
+-#| msgid "Error: Invalid option '%c'.\n"
+ msgid "uninstaller: Invalid option [%1]\n"
+-msgstr "Erreur : option « %c » invalide.\n"
++msgstr "uninstaller : option [%1] invalide\n"
+
+ #: uninstaller.rc:35
+ msgid ""
+@@ -13030,6 +13026,10 @@ msgid ""
+ "Uninstall applications from the current Wine prefix.\n"
+ "\n"
+ msgstr ""
++"Programme de désinstallation des applications Wine\n"
++"\n"
++"Désinstalle des applications du préfixe Wine courant.\n"
++"\n"
+
+ #: uninstaller.rc:43
+ msgid ""
+@@ -13044,6 +13044,17 @@ msgid ""
+ " [no option] Launch the graphical version of this program.\n"
+ "\n"
+ msgstr ""
++"Usage :\n"
++" uninstaller [options]\n"
++"\n"
++"Options :\n"
++" --help\t Afficher ces informations.\n"
++" --list\t Lister toutes les applications installées dans ce préfix "
++"Wine.\n"
++" --remove {GUID} Désinstaller l'application spécifiée.\n"
++"\t\t Utilisez « --list » pour déterminer le GUID de l'application.\n"
++" [aucune option] Lancer la version graphique de ce programme.\n"
++"\n"
+
+ #: view.rc:36
+ msgid "&Pan"
+diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c
+index 4d70ea9..1477287 100644
+--- a/programs/wineboot/wineboot.c
++++ b/programs/wineboot/wineboot.c
+@@ -85,8 +85,6 @@
+
+ WINE_DEFAULT_DEBUG_CHANNEL(wineboot);
+
+-#define MAX_LINE_LENGTH (2*MAX_PATH+2)
+-
+ extern BOOL shutdown_close_windows( BOOL force );
+ extern BOOL shutdown_all_desktops( BOOL force );
+ extern void kill_processes( BOOL kill_desktop );
+@@ -321,10 +319,10 @@ static void create_environment_registry_keys( void )
+ WCHAR buffer[60];
+ const WCHAR *arch;
+
+- NtQuerySystemInformation( SystemCpuInformation, &sci, sizeof(sci), NULL );
+-
+ if (RegCreateKeyW( HKEY_LOCAL_MACHINE, EnvironW, &env_key )) return;
+
++ NtQuerySystemInformation( SystemCpuInformation, &sci, sizeof(sci), NULL );
++
+ sprintfW( buffer, PercentDW, NtCurrentTeb()->Peb->NumberOfProcessors );
+ set_reg_value( env_key, NumProcW, buffer );
+
+diff --git a/programs/winecfg/resource.h b/programs/winecfg/resource.h
+index 8604fb4..9111d47 100644
+--- a/programs/winecfg/resource.h
++++ b/programs/winecfg/resource.h
+@@ -59,6 +59,7 @@
+ #define IDC_DESKTOP_HEIGHT 1024
+ #define IDC_DESKTOP_SIZE 1025
+ #define IDC_DESKTOP_BY 1026
++#define IDC_ENABLE_NATIVE_D3D9 1027
+
+ /* dll editing */
+ #define IDC_RAD_BUILTIN 1029
+diff --git a/programs/winecfg/winecfg.rc b/programs/winecfg/winecfg.rc
+index 221916b..077e323 100644
+--- a/programs/winecfg/winecfg.rc
++++ b/programs/winecfg/winecfg.rc
+@@ -176,6 +176,9 @@ BEGIN
+ EDITTEXT IDC_DESKTOP_WIDTH,84,68,40,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
+ EDITTEXT IDC_DESKTOP_HEIGHT,137,68,40,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
+
++ GROUPBOX "3D Acceleration",IDC_STATIC,8,180,244,32
++ CONTROL "Prefer native Direct3D 9 (requires Mesa with Nine state tracker)",IDC_ENABLE_NATIVE_D3D9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,196,230,8
++
+ GROUPBOX "Screen resolution",IDC_STATIC,8,95,244,84
+ CONTROL "", IDC_RES_TRACKBAR, "msctls_trackbar32",WS_TABSTOP,12,105,171,15
+ EDITTEXT IDC_RES_DPIEDIT,188,105,23,13,ES_NUMBER|WS_TABSTOP
+diff --git a/programs/winecfg/x11drvdlg.c b/programs/winecfg/x11drvdlg.c
+index 9a14fb6..81d91b8 100644
+--- a/programs/winecfg/x11drvdlg.c
++++ b/programs/winecfg/x11drvdlg.c
+@@ -46,6 +46,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
+ static const WCHAR logpixels_reg[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\','C','u','r','r','e','n','t','\\','S','o','f','t','w','a','r','e','\\','F','o','n','t','s',0};
+ static const WCHAR logpixels[] = {'L','o','g','P','i','x','e','l','s',0};
+
++static const WCHAR d3d9_reg[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','D','i','r','e','c','t','3','D',0};
++static const WCHAR d3d9[] = {'U','s','e','N','a','t','i','v','e',0};
++
+ static const WCHAR desktopW[] = {'D','e','s','k','t','o','p',0};
+ static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0};
+ static const WCHAR explorerW[] = {'E','x','p','l','o','r','e','r',0};
+@@ -67,6 +70,15 @@ static void convert_x11_desktop_key(void)
+ HeapFree(GetProcessHeap(), 0, buf);
+ }
+
++static INT read_Direct3D_reg(void)
++{
++ DWORD useNative;
++ WCHAR *buf = get_reg_keyW(HKEY_CURRENT_USER, d3d9_reg, d3d9, NULL);
++ useNative = buf ? *buf : 0;
++ HeapFree(GetProcessHeap(), 0, buf);
++ return useNative;
++}
++
+ static void update_gui_for_desktop_mode(HWND dialog)
+ {
+ WCHAR *buf, *bufindex;
+@@ -142,6 +154,11 @@ static void init_dialog(HWND dialog)
+ CheckDlgButton(dialog, IDC_ENABLE_DECORATED, BST_UNCHECKED);
+ HeapFree(GetProcessHeap(), 0, buf);
+
++ if (read_Direct3D_reg())
++ CheckDlgButton(dialog, IDC_ENABLE_NATIVE_D3D9, BST_CHECKED);
++ else
++ CheckDlgButton(dialog, IDC_ENABLE_NATIVE_D3D9, BST_UNCHECKED);
++
+ updating_ui = FALSE;
+ }
+
+@@ -233,6 +250,14 @@ static void on_fullscreen_grab_clicked(HWND dialog)
+ set_reg_key(config_key, keypath("X11 Driver"), "GrabFullscreen", "N");
+ }
+
++static void on_enable_native_d3d9_clicked(HWND dialog)
++{
++ if (IsDlgButtonChecked(dialog, IDC_ENABLE_NATIVE_D3D9) == BST_CHECKED)
++ set_reg_key_dwordW(HKEY_CURRENT_USER, d3d9_reg, d3d9, 1);
++ else
++ set_reg_key_dwordW(HKEY_CURRENT_USER, d3d9_reg, d3d9, 0);
++}
++
+ static INT read_logpixels_reg(void)
+ {
+ DWORD dwLogPixels;
+@@ -378,6 +403,7 @@ GraphDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ case IDC_ENABLE_MANAGED: on_enable_managed_clicked(hDlg); break;
+ case IDC_ENABLE_DECORATED: on_enable_decorated_clicked(hDlg); break;
+ case IDC_FULLSCREEN_GRAB: on_fullscreen_grab_clicked(hDlg); break;
++ case IDC_ENABLE_NATIVE_D3D9: on_enable_native_d3d9_clicked(hDlg); break;
+ }
+ break;
+ }
+diff --git a/server/fd.c b/server/fd.c
+index 6c78a0a..fe778f1 100644
+--- a/server/fd.c
++++ b/server/fd.c
+@@ -44,10 +44,7 @@
+ #include <sys/statvfs.h>
+ #endif
+ #ifdef HAVE_SYS_VFS_H
+-/*
+- * Solaris defines its system list in sys/list.h.
+- * This need to be workaround it here.
+- */
++/* Work around a conflict with Solaris' system list defined in sys/list.h. */
+ #define list SYSLIST
+ #define list_next SYSLIST_NEXT
+ #define list_prev SYSLIST_PREV
diff --git a/wine/build/patches/wine-d3d9-1.8.patch b/wine/build/patches/wine-d3d9-1.8.patch
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/wine/build/patches/wine-d3d9-1.8.patch