diff options
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 |
commit | a31f3babf9cd99c443eb6e5a8228f93a76b87cb1 (patch) | |
tree | b645ed5c8f5f27b9ca317dd671dd08e32fd354e2 | |
parent | 32c218ce98434be5e28fec6046c37a4bfcaaafdf (diff) | |
download | asb-a31f3babf9cd99c443eb6e5a8228f93a76b87cb1.tar.gz asb-a31f3babf9cd99c443eb6e5a8228f93a76b87cb1.tar.xz |
Initial revision
-rw-r--r-- | wine/build/patches/wine-d3d9-1.7.51.patch | 4436 | ||||
-rw-r--r-- | wine/build/patches/wine-d3d9-1.7.52.patch | 9951 | ||||
-rw-r--r-- | wine/build/patches/wine-d3d9-1.8.patch | 0 |
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", ®key)) { ++ DWORD type, data; ++ DWORD size = sizeof(DWORD); ++ ++ if (!RegQueryValueExA(regkey, "VideoPciDeviceID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD))) ++ pIdentifier->DeviceId = data; ++ if(size != sizeof(DWORD)) { ++ ERR("VideoPciDeviceID is not a DWORD\n"); ++ size = sizeof(DWORD); ++ } ++ if (!RegQueryValueExA(regkey, "VideoPciVendorID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD))) ++ pIdentifier->VendorId = data; ++ if(size != sizeof(DWORD)) ++ ERR("VideoPciVendorID is not a DWORD\n"); ++ RegCloseKey(regkey); ++ ++ TRACE("DeviceId:VendorId overridden: %04X:%04X\n", pIdentifier->DeviceId, pIdentifier->VendorId); ++ } ++ } ++ return hr; ++} ++ ++static UINT WINAPI ++d3dadapter9_GetAdapterModeCount( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DFORMAT Format ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { ++ WARN("Adapter %u does not exist.\n", Adapter); ++ return 0; ++ } ++ if (FAILED(d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL, ++ Format, D3DUSAGE_RENDERTARGET, ++ D3DRTYPE_SURFACE, Format))) { ++ WARN("DeviceFormat not available.\n"); ++ return 0; ++ } ++ ++ TRACE("%u modes.\n", ADAPTER_OUTPUT.nmodes); ++ return ADAPTER_OUTPUT.nmodes; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_EnumAdapterModes( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DFORMAT Format, ++ UINT Mode, ++ D3DDISPLAYMODE *pMode ) ++{ ++ HRESULT hr; ++ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { ++ WARN("Adapter %u does not exist.\n", Adapter); ++ return D3DERR_INVALIDCALL; ++ } ++ ++ hr = d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL, ++ Format, D3DUSAGE_RENDERTARGET, ++ D3DRTYPE_SURFACE, Format); ++ if (FAILED(hr)) { ++ TRACE("DeviceFormat not available.\n"); ++ return hr; ++ } ++ ++ if (Mode >= ADAPTER_OUTPUT.nmodes) { ++ WARN("Mode %u does not exist.\n", Mode); ++ return D3DERR_INVALIDCALL; ++ } ++ ++ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; ++ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; ++ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; ++ pMode->Format = Format; ++ ++ return D3D_OK; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_GetAdapterDisplayMode( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDISPLAYMODE *pMode ) ++{ ++ UINT Mode; ++ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { ++ WARN("Adapter %u does not exist.\n", Adapter); ++ return D3DERR_INVALIDCALL; ++ } ++ ++ Mode = ADAPTER_OUTPUT.current; ++ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; ++ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; ++ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; ++ pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format; ++ ++ return D3D_OK; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDeviceType( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DevType, ++ D3DFORMAT AdapterFormat, ++ D3DFORMAT BackBufferFormat, ++ BOOL bWindowed ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDeviceType, ++ DevType, AdapterFormat, BackBufferFormat, bWindowed); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DFORMAT AdapterFormat, ++ DWORD Usage, ++ D3DRESOURCETYPE RType, ++ D3DFORMAT CheckFormat ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDeviceFormat, ++ DeviceType, AdapterFormat, Usage, RType, CheckFormat); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDeviceMultiSampleType( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DFORMAT SurfaceFormat, ++ BOOL Windowed, ++ D3DMULTISAMPLE_TYPE MultiSampleType, ++ DWORD *pQualityLevels ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDeviceMultiSampleType, DeviceType, SurfaceFormat, ++ Windowed, MultiSampleType, pQualityLevels); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDepthStencilMatch( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DFORMAT AdapterFormat, ++ D3DFORMAT RenderTargetFormat, ++ D3DFORMAT DepthStencilFormat ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDepthStencilMatch, DeviceType, AdapterFormat, ++ RenderTargetFormat, DepthStencilFormat); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDeviceFormatConversion( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DFORMAT SourceFormat, ++ D3DFORMAT TargetFormat ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDeviceFormatConversion, ++ DeviceType, SourceFormat, TargetFormat); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_GetDeviceCaps( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DCAPS9 *pCaps ) ++{ ++ HRESULT hr; ++ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ ++ hr = ADAPTER_PROC(GetDeviceCaps, DeviceType, pCaps); ++ if (FAILED(hr)) { return hr; } ++ ++ pCaps->MasterAdapterOrdinal = This->map[Adapter].master; ++ pCaps->AdapterOrdinalInGroup = Adapter-This->map[Adapter].master; ++ pCaps->NumberOfAdaptersInGroup = ADAPTER_GROUP.noutputs; ++ ++ return hr; ++} ++ ++static HMONITOR WINAPI ++d3dadapter9_GetAdapterMonitor( struct d3dadapter9 *This, ++ UINT Adapter ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return (HMONITOR)0; } ++ return (HMONITOR)ADAPTER_OUTPUT.monitor; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ HWND hFocusWindow, ++ DWORD BehaviorFlags, ++ D3DPRESENT_PARAMETERS *pPresentationParameters, ++ D3DDISPLAYMODEEX *pFullscreenDisplayMode, ++ IDirect3DDevice9Ex **ppReturnedDeviceInterface ); ++ ++static HRESULT WINAPI ++d3dadapter9_CreateDevice( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ HWND hFocusWindow, ++ DWORD BehaviorFlags, ++ D3DPRESENT_PARAMETERS *pPresentationParameters, ++ IDirect3DDevice9 **ppReturnedDeviceInterface ) ++{ ++ HRESULT hr; ++ hr = d3dadapter9_CreateDeviceEx(This, Adapter, DeviceType, hFocusWindow, ++ BehaviorFlags, pPresentationParameters, ++ NULL, ++ (IDirect3DDevice9Ex **)ppReturnedDeviceInterface); ++ if (FAILED(hr)) ++ return hr; ++ return D3D_OK; ++} ++ ++static UINT WINAPI ++d3dadapter9_GetAdapterModeCountEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ const D3DDISPLAYMODEFILTER *pFilter ) ++{ ++ return 1; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_EnumAdapterModesEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ const D3DDISPLAYMODEFILTER *pFilter, ++ UINT Mode, ++ D3DDISPLAYMODEEX *pMode ) ++{ ++ FIXME("(%p, %u, %p, %u, %p), stub!\n", This, Adapter, pFilter, Mode, pMode); ++ return D3DERR_INVALIDCALL; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_GetAdapterDisplayModeEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDISPLAYMODEEX *pMode, ++ D3DDISPLAYROTATION *pRotation ) ++{ ++ FIXME("(%p, %u, %p, %p), stub!\n", This, Adapter, pMode, pRotation); ++ return D3DERR_INVALIDCALL; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ HWND hFocusWindow, ++ DWORD BehaviorFlags, ++ D3DPRESENT_PARAMETERS *pPresentationParameters, ++ D3DDISPLAYMODEEX *pFullscreenDisplayMode, ++ IDirect3DDevice9Ex **ppReturnedDeviceInterface ) ++{ ++ ID3DPresentGroup *present; ++ HRESULT hr; ++ ++ 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, ¶ms[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", ®key)) { ++ DWORD type, data; ++ DWORD size = sizeof(DWORD); ++ ++ if (!RegQueryValueExA(regkey, "VideoPciDeviceID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD))) ++ pIdentifier->DeviceId = data; ++ if(size != sizeof(DWORD)) { ++ ERR("VideoPciDeviceID is not a DWORD\n"); ++ size = sizeof(DWORD); ++ } ++ if (!RegQueryValueExA(regkey, "VideoPciVendorID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD))) ++ pIdentifier->VendorId = data; ++ if(size != sizeof(DWORD)) ++ ERR("VideoPciVendorID is not a DWORD\n"); ++ RegCloseKey(regkey); ++ ++ TRACE("DeviceId:VendorId overridden: %04X:%04X\n", pIdentifier->DeviceId, pIdentifier->VendorId); ++ } ++ } ++ return hr; ++} ++ ++static UINT WINAPI ++d3dadapter9_GetAdapterModeCount( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DFORMAT Format ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { ++ WARN("Adapter %u does not exist.\n", Adapter); ++ return 0; ++ } ++ if (FAILED(d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL, ++ Format, D3DUSAGE_RENDERTARGET, ++ D3DRTYPE_SURFACE, Format))) { ++ WARN("DeviceFormat not available.\n"); ++ return 0; ++ } ++ ++ TRACE("%u modes.\n", ADAPTER_OUTPUT.nmodes); ++ return ADAPTER_OUTPUT.nmodes; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_EnumAdapterModes( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DFORMAT Format, ++ UINT Mode, ++ D3DDISPLAYMODE *pMode ) ++{ ++ HRESULT hr; ++ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { ++ WARN("Adapter %u does not exist.\n", Adapter); ++ return D3DERR_INVALIDCALL; ++ } ++ ++ hr = d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL, ++ Format, D3DUSAGE_RENDERTARGET, ++ D3DRTYPE_SURFACE, Format); ++ if (FAILED(hr)) { ++ TRACE("DeviceFormat not available.\n"); ++ return hr; ++ } ++ ++ if (Mode >= ADAPTER_OUTPUT.nmodes) { ++ WARN("Mode %u does not exist.\n", Mode); ++ return D3DERR_INVALIDCALL; ++ } ++ ++ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; ++ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; ++ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; ++ pMode->Format = Format; ++ ++ return D3D_OK; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_GetAdapterDisplayMode( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDISPLAYMODE *pMode ) ++{ ++ UINT Mode; ++ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { ++ WARN("Adapter %u does not exist.\n", Adapter); ++ return D3DERR_INVALIDCALL; ++ } ++ ++ Mode = ADAPTER_OUTPUT.current; ++ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; ++ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; ++ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; ++ pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format; ++ ++ return D3D_OK; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDeviceType( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DevType, ++ D3DFORMAT AdapterFormat, ++ D3DFORMAT BackBufferFormat, ++ BOOL bWindowed ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDeviceType, ++ DevType, AdapterFormat, BackBufferFormat, bWindowed); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DFORMAT AdapterFormat, ++ DWORD Usage, ++ D3DRESOURCETYPE RType, ++ D3DFORMAT CheckFormat ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDeviceFormat, ++ DeviceType, AdapterFormat, Usage, RType, CheckFormat); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDeviceMultiSampleType( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DFORMAT SurfaceFormat, ++ BOOL Windowed, ++ D3DMULTISAMPLE_TYPE MultiSampleType, ++ DWORD *pQualityLevels ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDeviceMultiSampleType, DeviceType, SurfaceFormat, ++ Windowed, MultiSampleType, pQualityLevels); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDepthStencilMatch( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DFORMAT AdapterFormat, ++ D3DFORMAT RenderTargetFormat, ++ D3DFORMAT DepthStencilFormat ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDepthStencilMatch, DeviceType, AdapterFormat, ++ RenderTargetFormat, DepthStencilFormat); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CheckDeviceFormatConversion( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DFORMAT SourceFormat, ++ D3DFORMAT TargetFormat ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ return ADAPTER_PROC(CheckDeviceFormatConversion, ++ DeviceType, SourceFormat, TargetFormat); ++} ++ ++static HRESULT WINAPI ++d3dadapter9_GetDeviceCaps( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ D3DCAPS9 *pCaps ) ++{ ++ HRESULT hr; ++ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } ++ ++ hr = ADAPTER_PROC(GetDeviceCaps, DeviceType, pCaps); ++ if (FAILED(hr)) { return hr; } ++ ++ pCaps->MasterAdapterOrdinal = This->map[Adapter].master; ++ pCaps->AdapterOrdinalInGroup = Adapter-This->map[Adapter].master; ++ pCaps->NumberOfAdaptersInGroup = ADAPTER_GROUP.noutputs; ++ ++ return hr; ++} ++ ++static HMONITOR WINAPI ++d3dadapter9_GetAdapterMonitor( struct d3dadapter9 *This, ++ UINT Adapter ) ++{ ++ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return (HMONITOR)0; } ++ return (HMONITOR)ADAPTER_OUTPUT.monitor; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ HWND hFocusWindow, ++ DWORD BehaviorFlags, ++ D3DPRESENT_PARAMETERS *pPresentationParameters, ++ D3DDISPLAYMODEEX *pFullscreenDisplayMode, ++ IDirect3DDevice9Ex **ppReturnedDeviceInterface ); ++ ++static HRESULT WINAPI ++d3dadapter9_CreateDevice( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ HWND hFocusWindow, ++ DWORD BehaviorFlags, ++ D3DPRESENT_PARAMETERS *pPresentationParameters, ++ IDirect3DDevice9 **ppReturnedDeviceInterface ) ++{ ++ HRESULT hr; ++ hr = d3dadapter9_CreateDeviceEx(This, Adapter, DeviceType, hFocusWindow, ++ BehaviorFlags, pPresentationParameters, ++ NULL, ++ (IDirect3DDevice9Ex **)ppReturnedDeviceInterface); ++ if (FAILED(hr)) ++ return hr; ++ return D3D_OK; ++} ++ ++static UINT WINAPI ++d3dadapter9_GetAdapterModeCountEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ const D3DDISPLAYMODEFILTER *pFilter ) ++{ ++ return 1; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_EnumAdapterModesEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ const D3DDISPLAYMODEFILTER *pFilter, ++ UINT Mode, ++ D3DDISPLAYMODEEX *pMode ) ++{ ++ FIXME("(%p, %u, %p, %u, %p), stub!\n", This, Adapter, pFilter, Mode, pMode); ++ return D3DERR_INVALIDCALL; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_GetAdapterDisplayModeEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDISPLAYMODEEX *pMode, ++ D3DDISPLAYROTATION *pRotation ) ++{ ++ FIXME("(%p, %u, %p, %p), stub!\n", This, Adapter, pMode, pRotation); ++ return D3DERR_INVALIDCALL; ++} ++ ++static HRESULT WINAPI ++d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This, ++ UINT Adapter, ++ D3DDEVTYPE DeviceType, ++ HWND hFocusWindow, ++ DWORD BehaviorFlags, ++ D3DPRESENT_PARAMETERS *pPresentationParameters, ++ D3DDISPLAYMODEEX *pFullscreenDisplayMode, ++ IDirect3DDevice9Ex **ppReturnedDeviceInterface ) ++{ ++ ID3DPresentGroup *present; ++ HRESULT hr; ++ ++ 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, ¶ms[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 |