diff options
Diffstat (limited to 'app-emulation/wine/files/wine-1.7.55-d3d9.patch')
-rw-r--r-- | app-emulation/wine/files/wine-1.7.55-d3d9.patch | 5366 |
1 files changed, 0 insertions, 5366 deletions
diff --git a/app-emulation/wine/files/wine-1.7.55-d3d9.patch b/app-emulation/wine/files/wine-1.7.55-d3d9.patch deleted file mode 100644 index 7497964b..00000000 --- a/app-emulation/wine/files/wine-1.7.55-d3d9.patch +++ /dev/null @@ -1,5366 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index 2d2a168..5f75a99 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -65,6 +65,8 @@ AC_ARG_WITH(openal, AS_HELP_STRING([--without-openal],[do not use OpenAL]), - AC_ARG_WITH(opencl, AS_HELP_STRING([--without-opencl],[do not use OpenCL]), - [if test "x$withval" = "xno"; then ac_cv_header_CL_cl_h=no; ac_cv_header_OpenCL_opencl_h=no; fi]) - AC_ARG_WITH(opengl, AS_HELP_STRING([--without-opengl],[do not use OpenGL])) -+AC_ARG_WITH(d3dadapter,AS_HELP_STRING([--without-d3dadapter],[do not use native Direct3D])) -+AC_ARG_WITH(d3dadapter-dri2-fallback, AS_HELP_STRING([--without-d3dadapter-dri2-fallback],[add a DRI2 fallback to d3dadapter DRI3 code])) - AC_ARG_WITH(osmesa, AS_HELP_STRING([--without-osmesa],[do not use the OSMesa library])) - AC_ARG_WITH(oss, AS_HELP_STRING([--without-oss],[do not use the OSS sound support])) - AC_ARG_WITH(pcap, AS_HELP_STRING([--without-pcap],[do not use the Packet Capture library]), -@@ -381,6 +383,8 @@ AC_CHECK_LIB(ossaudio,_oss_ioctl) - - AC_SUBST(OPENGL_LIBS,"") - -+AC_SUBST(D3DADAPTER9_LIBS,"") -+ - dnl **** Check for header files **** - - AC_SYS_LARGEFILE() -@@ -1156,6 +1160,45 @@ This probably prevents linking to OpenGL. Try deleting the file and restarting c - WINE_WARNING_WITH(opengl,[test -n "$opengl_msg"],[$opengl_msg - OpenGL and Direct3D won't be supported.]) - -+ -+ -+ dnl Check for d3dadapter -+ if test "x$with_d3dadapter" != "xno" -+ then -+ D3D_CFLAGS=`pkg-config --cflags d3d` -+ D3D_LIBS=`pkg-config --libs d3d` -+ AC_SUBST(D3D_CFLAGS) -+ AC_SUBST(D3D_LIBS) -+ AC_DEFINE(SONAME_D3DADAPTER9, ["d3dadapter9.so.1"], ["temporary hack"]) -+ AC_DEFINE_UNQUOTED(D3D_MODULE_DIR, ["`pkg-config --variable=moduledir d3d`"], ["module dir"]) -+ D3DADAPTER9_LIBS="" -+ WINE_CHECK_SONAME(xcb,xcb_request_check, [D3DADAPTER9_LIBS="-lxcb $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb "],[D3Dadapter9 requires libxcb]) -+ WINE_CHECK_SONAME(xcb-dri3,xcb_dri3_open, [D3DADAPTER9_LIBS="-lxcb-dri3 $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb-dri3 -lxcb "],[D3Dadapter9 requires libxcb-dri3]) -+ WINE_CHECK_SONAME(xcb-present,xcb_present_notify_msc, [D3DADAPTER9_LIBS="-lxcb-present $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libxcb-present]) -+ WINE_CHECK_SONAME(X11-xcb,XGetXCBConnection, [D3DADAPTER9_LIBS="-lX11-xcb $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libX11-xcb]) -+ WINE_CHECK_SONAME(xcb-xfixes,xcb_xfixes_create_region, [D3DADAPTER9_LIBS="-lxcb-xfixes $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libxcb-xfixes]) -+ WINE_CHECK_SONAME(X11,XOpenDisplay, [D3DADAPTER9_LIBS="-lX11 $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libX11]) -+ WINE_CHECK_SONAME(Xext,XextRemoveDisplay, [D3DADAPTER9_LIBS="-lXext $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lXext -lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libXext]) -+ WINE_CHECK_SONAME(pthread,pthread_mutex_lock, [D3DADAPTER9_LIBS="-lpthread $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lpthread -lXext -lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 requires libpthread]) -+ -+ if test "x$with_d3dadapter_dri2_fallback" != "xno" -+ then -+ AC_DEFINE(D3DADAPTER9_DRI2, 1, [Whether d3dadapter9 DRI2 fallback is compiled]) -+ WINE_CHECK_SONAME(GL,glGenFramebuffers, [D3DADAPTER9_LIBS="-lGL $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lGL -lpthread -lXext -lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 DRI2 fallback requires libGL]) -+ WINE_CHECK_SONAME(EGL,eglCreateContext, [D3DADAPTER9_LIBS="-lEGL $D3DADAPTER9_LIBS"]) -+ WINE_ERROR_WITH(d3dadapter,[test "x$D3DADAPTER9_LIBS" != "x-lEGL -lGL -lpthread -lXext -lX11 -lxcb-xfixes -lX11-xcb -lxcb-present -lxcb-dri3 -lxcb "],[D3Dadapter9 DRI2 fallback requires libEGL]) -+ fi -+ fi -+ - CPPFLAGS="$ac_save_CPPFLAGS" - else - X_CFLAGS="" -@@ -2764,6 +2807,7 @@ WINE_CONFIG_DLL(d3d8,,[implib]) - WINE_CONFIG_TEST(dlls/d3d8/tests) - WINE_CONFIG_DLL(d3d9,,[implib]) - WINE_CONFIG_TEST(dlls/d3d9/tests) -+WINE_CONFIG_DLL(d3d9-nine,,[implib]) - WINE_CONFIG_DLL(d3dcompiler_33) - WINE_CONFIG_DLL(d3dcompiler_34) - WINE_CONFIG_DLL(d3dcompiler_35) -diff --git a/dlls/d3d9-nine/Makefile.in b/dlls/d3d9-nine/Makefile.in -new file mode 100644 -index 0000000..a761cd7 ---- /dev/null -+++ b/dlls/d3d9-nine/Makefile.in -@@ -0,0 +1,12 @@ -+MODULE = d3d9-nine.dll -+IMPORTS = dxguid uuid advapi32 gdi32 user32 -+EXTRAINCL = $(X_CFLAGS) -+EXTRALIBS = $(D3DADAPTER9_LIBS) -+ -+C_SRCS = \ -+ d3d9_main.c \ -+ d3dadapter9.c \ -+ present.c \ -+ dri3.c -+ -+RC_SRCS = version.rc -diff --git a/dlls/d3d9-nine/d3d9-nine.spec b/dlls/d3d9-nine/d3d9-nine.spec -new file mode 100644 -index 0000000..a33cba5 ---- /dev/null -+++ b/dlls/d3d9-nine/d3d9-nine.spec -@@ -0,0 +1,14 @@ -+@ stdcall Direct3DShaderValidatorCreate9() -+@ stub PSGPError -+@ stub PSGPSampleTexture -+@ stdcall D3DPERF_BeginEvent(long wstr) -+@ stdcall D3DPERF_EndEvent() -+@ stdcall D3DPERF_GetStatus() -+@ stdcall D3DPERF_QueryRepeatFrame() -+@ stdcall D3DPERF_SetMarker(long wstr) -+@ stdcall D3DPERF_SetOptions(long) -+@ stdcall D3DPERF_SetRegion(long wstr) -+@ stub DebugSetLevel -+@ stdcall DebugSetMute() -+@ stdcall Direct3DCreate9(long) -+@ stdcall Direct3DCreate9Ex(long ptr) -diff --git a/dlls/d3d9-nine/d3d9_main.c b/dlls/d3d9-nine/d3d9_main.c -new file mode 100644 -index 0000000..de20475 ---- /dev/null -+++ b/dlls/d3d9-nine/d3d9_main.c -@@ -0,0 +1,163 @@ -+/* -+ * Direct3D 9 -+ * -+ * Copyright 2002-2003 Jason Edmeades -+ * Copyright 2002-2003 Raphael Junqueira -+ * Copyright 2005 Oliver Stieber -+ * Copyright 2015 Patrick Rudolph -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ * -+ */ -+ -+#include "config.h" -+#include "initguid.h" -+#include "wine/debug.h" -+ -+#include <dlfcn.h> -+#include <fcntl.h> -+#include <stdarg.h> -+#include <stdio.h> -+#include <stdlib.h> -+ -+#include <d3dadapter/d3dadapter9.h> -+ -+#include "d3dadapter9.h" -+ -+#include "wine/library.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter); -+ -+static int D3DPERF_event_level = 0; -+static Display *gdi_display; -+ -+void WINAPI DebugSetMute(void) { -+ /* nothing to do */ -+} -+ -+IDirect3D9 * WINAPI DECLSPEC_HOTPATCH Direct3DCreate9(UINT sdk_version) -+{ -+ IDirect3D9 *native; -+ TRACE("sdk_version %#x.\n", sdk_version); -+ -+ if (SUCCEEDED(d3dadapter9_new(gdi_display, FALSE, (IDirect3D9Ex **)&native))) { -+ return native; -+ } -+ -+ return NULL; -+} -+ -+HRESULT WINAPI DECLSPEC_HOTPATCH Direct3DCreate9Ex(UINT sdk_version, IDirect3D9Ex **d3d9ex) -+{ -+ TRACE("sdk_version %#x, d3d9ex %p.\n", sdk_version, d3d9ex); -+ -+ return d3dadapter9_new(gdi_display, TRUE, d3d9ex); -+} -+ -+/******************************************************************* -+ * Direct3DShaderValidatorCreate9 (D3D9.@) -+ * -+ * No documentation available for this function. -+ * SDK only says it is internal and shouldn't be used. -+ */ -+void* WINAPI Direct3DShaderValidatorCreate9(void) -+{ -+ static int once; -+ -+ if (!once++) FIXME("stub\n"); -+ return NULL; -+} -+ -+/******************************************************************* -+ * DllMain -+ */ -+BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) -+{ -+ switch (reason) -+ { -+ case DLL_PROCESS_ATTACH: -+ if (!(gdi_display = XOpenDisplay( NULL ))) { -+ ERR("Failed to open display\n"); -+ return FALSE; -+ } -+ -+ fcntl( ConnectionNumber(gdi_display), F_SETFD, 1 ); /* set close on exec flag */ -+ break; -+ } -+ -+ return TRUE; -+} -+ -+/*********************************************************************** -+ * D3DPERF_BeginEvent (D3D9.@) -+ */ -+int WINAPI D3DPERF_BeginEvent(D3DCOLOR color, const WCHAR *name) -+{ -+ TRACE("color 0x%08x, name %s.\n", color, debugstr_w(name)); -+ -+ return D3DPERF_event_level++; -+} -+ -+/*********************************************************************** -+ * D3DPERF_EndEvent (D3D9.@) -+ */ -+int WINAPI D3DPERF_EndEvent(void) { -+ TRACE("(void) : stub\n"); -+ -+ return --D3DPERF_event_level; -+} -+ -+/*********************************************************************** -+ * D3DPERF_GetStatus (D3D9.@) -+ */ -+DWORD WINAPI D3DPERF_GetStatus(void) { -+ FIXME("(void) : stub\n"); -+ -+ return 0; -+} -+ -+/*********************************************************************** -+ * D3DPERF_SetOptions (D3D9.@) -+ * -+ */ -+void WINAPI D3DPERF_SetOptions(DWORD options) -+{ -+ FIXME("(%#x) : stub\n", options); -+} -+ -+/*********************************************************************** -+ * D3DPERF_QueryRepeatFrame (D3D9.@) -+ */ -+BOOL WINAPI D3DPERF_QueryRepeatFrame(void) { -+ FIXME("(void) : stub\n"); -+ -+ return FALSE; -+} -+ -+/*********************************************************************** -+ * D3DPERF_SetMarker (D3D9.@) -+ */ -+void WINAPI D3DPERF_SetMarker(D3DCOLOR color, const WCHAR *name) -+{ -+ FIXME("color 0x%08x, name %s stub!\n", color, debugstr_w(name)); -+} -+ -+/*********************************************************************** -+ * D3DPERF_SetRegion (D3D9.@) -+ */ -+void WINAPI D3DPERF_SetRegion(D3DCOLOR color, const WCHAR *name) -+{ -+ FIXME("color 0x%08x, name %s stub!\n", color, debugstr_w(name)); -+} -diff --git a/dlls/d3d9-nine/d3dadapter9.c b/dlls/d3d9-nine/d3dadapter9.c -new file mode 100644 -index 0000000..f15e44f ---- /dev/null -+++ b/dlls/d3d9-nine/d3dadapter9.c -@@ -0,0 +1,865 @@ -+/* -+ * Wine IDirect3D9 interface using ID3DAdapter9 -+ * -+ * Copyright 2013 Joakim Sindholt -+ * Christoph Bumiller -+ * Copyright 2014 David Heidelberger -+ * Copyright 2014-2015 Axel Davy -+ * Copyright 2015 Nick Sarnie -+ * Patrick Rudolph -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#include "config.h" -+#include "wine/debug.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter); -+ -+#include <d3dadapter/d3dadapter9.h> -+#include "present.h" -+ -+/* this represents a snapshot taken at the moment of creation */ -+struct output -+{ -+ D3DDISPLAYROTATION rotation; /* current rotation */ -+ D3DDISPLAYMODEEX *modes; -+ unsigned nmodes; -+ unsigned nmodesalloc; -+ unsigned current; /* current mode num */ -+ -+ HMONITOR monitor; -+}; -+ -+struct adapter_group -+{ -+ struct output *outputs; -+ unsigned noutputs; -+ unsigned noutputsalloc; -+ -+ /* override driver provided DeviceName with this to homogenize device names -+ * with wine */ -+ WCHAR devname[32]; -+ -+ /* driver stuff */ -+ ID3DAdapter9 *adapter; -+}; -+ -+struct adapter_map -+{ -+ unsigned group; -+ unsigned master; -+}; -+ -+struct d3dadapter9 -+{ -+ /* COM vtable */ -+ void *vtable; -+ /* IUnknown reference count */ -+ LONG refs; -+ -+ /* adapter groups and mappings */ -+ struct adapter_group *groups; -+ struct adapter_map *map; -+ unsigned nadapters; -+ unsigned ngroups; -+ unsigned ngroupsalloc; -+ -+ /* true if it implements IDirect3D9Ex */ -+ boolean ex; -+ Display *gdi_display; -+}; -+ -+/* convenience wrapper for calls into ID3D9Adapter */ -+#define ADAPTER_GROUP \ -+ This->groups[This->map[Adapter].group] -+ -+#define ADAPTER_PROC(name, ...) \ -+ ID3DAdapter9_##name(ADAPTER_GROUP.adapter, ## __VA_ARGS__) -+ -+#define ADAPTER_OUTPUT \ -+ ADAPTER_GROUP.outputs[Adapter-This->map[Adapter].master] -+ -+static HRESULT WINAPI -+d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DeviceType, -+ D3DFORMAT AdapterFormat, -+ DWORD Usage, -+ D3DRESOURCETYPE RType, -+ D3DFORMAT CheckFormat ); -+ -+static ULONG WINAPI -+d3dadapter9_AddRef( struct d3dadapter9 *This ) -+{ -+ ULONG refs = InterlockedIncrement(&This->refs); -+ TRACE("%p increasing refcount to %u.\n", This, refs); -+ return refs; -+} -+ -+static ULONG WINAPI -+d3dadapter9_Release( struct d3dadapter9 *This ) -+{ -+ ULONG refs = InterlockedDecrement(&This->refs); -+ TRACE("%p decreasing refcount to %u.\n", This, refs); -+ if (refs == 0) { -+ /* dtor */ -+ if (This->map) { -+ HeapFree(GetProcessHeap(), 0, This->map); -+ } -+ -+ if (This->groups) { -+ int i, j; -+ for (i = 0; i < This->ngroups; ++i) { -+ if (This->groups[i].outputs) { -+ for (j = 0; j < This->groups[i].noutputs; ++j) { -+ if (This->groups[i].outputs[j].modes) { -+ HeapFree(GetProcessHeap(), 0, -+ This->groups[i].outputs[j].modes); -+ } -+ } -+ HeapFree(GetProcessHeap(), 0, This->groups[i].outputs); -+ } -+ -+ if (This->groups[i].adapter) { -+ ID3DAdapter9_Release(This->groups[i].adapter); -+ } -+ } -+ HeapFree(GetProcessHeap(), 0, This->groups); -+ } -+ -+ HeapFree(GetProcessHeap(), 0, This); -+ } -+ return refs; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_QueryInterface( struct d3dadapter9 *This, -+ REFIID riid, -+ void **ppvObject ) -+{ -+ if (!ppvObject) { return E_POINTER; } -+ if ((IsEqualGUID(&IID_IDirect3D9Ex, riid) && This->ex) || -+ IsEqualGUID(&IID_IDirect3D9, riid) || -+ IsEqualGUID(&IID_IUnknown, riid)) { -+ *ppvObject = This; -+ d3dadapter9_AddRef(This); -+ return S_OK; -+ } -+ -+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); -+ *ppvObject = NULL; -+ -+ return E_NOINTERFACE; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_RegisterSoftwareDevice( struct d3dadapter9 *This, -+ void *pInitializeFunction ) -+{ -+ FIXME("(%p, %p), stub!\n", This, pInitializeFunction); -+ return D3DERR_INVALIDCALL; -+} -+ -+static UINT WINAPI -+d3dadapter9_GetAdapterCount( struct d3dadapter9 *This ) -+{ -+ return This->nadapters; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_GetAdapterIdentifier( struct d3dadapter9 *This, -+ UINT Adapter, -+ DWORD Flags, -+ D3DADAPTER_IDENTIFIER9 *pIdentifier ) -+{ -+ HRESULT hr; -+ HKEY regkey; -+ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } -+ -+ hr = ADAPTER_PROC(GetAdapterIdentifier, Flags, pIdentifier); -+ if (SUCCEEDED(hr)) { -+ /* Override the driver provided DeviceName with what Wine provided */ -+ ZeroMemory(pIdentifier->DeviceName, sizeof(pIdentifier->DeviceName)); -+ if (!WideCharToMultiByte(CP_ACP, 0, ADAPTER_GROUP.devname, -1, -+ pIdentifier->DeviceName, -+ sizeof(pIdentifier->DeviceName), -+ NULL, NULL)) { -+ /* Wine does it */ -+ return D3DERR_INVALIDCALL; -+ } -+ TRACE("DeviceName overriden: %s\n", pIdentifier->DeviceName); -+ -+ /* Override PCI IDs when wined3d registry keys are set */ -+ if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", ®key)) { -+ DWORD type, data; -+ DWORD size = sizeof(DWORD); -+ -+ if (!RegQueryValueExA(regkey, "VideoPciDeviceID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD))) -+ pIdentifier->DeviceId = data; -+ if(size != sizeof(DWORD)) { -+ ERR("VideoPciDeviceID is not a DWORD\n"); -+ size = sizeof(DWORD); -+ } -+ if (!RegQueryValueExA(regkey, "VideoPciVendorID", 0, &type, (BYTE *)&data, &size) && (type == REG_DWORD) && (size == sizeof(DWORD))) -+ pIdentifier->VendorId = data; -+ if(size != sizeof(DWORD)) -+ ERR("VideoPciVendorID is not a DWORD\n"); -+ RegCloseKey(regkey); -+ -+ TRACE("DeviceId:VendorId overridden: %04X:%04X\n", pIdentifier->DeviceId, pIdentifier->VendorId); -+ } -+ } -+ return hr; -+} -+ -+static UINT WINAPI -+d3dadapter9_GetAdapterModeCount( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DFORMAT Format ) -+{ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { -+ WARN("Adapter %u does not exist.\n", Adapter); -+ return 0; -+ } -+ if (FAILED(d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL, -+ Format, D3DUSAGE_RENDERTARGET, -+ D3DRTYPE_SURFACE, Format))) { -+ WARN("DeviceFormat not available.\n"); -+ return 0; -+ } -+ -+ TRACE("%u modes.\n", ADAPTER_OUTPUT.nmodes); -+ return ADAPTER_OUTPUT.nmodes; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_EnumAdapterModes( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DFORMAT Format, -+ UINT Mode, -+ D3DDISPLAYMODE *pMode ) -+{ -+ HRESULT hr; -+ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { -+ WARN("Adapter %u does not exist.\n", Adapter); -+ return D3DERR_INVALIDCALL; -+ } -+ -+ hr = d3dadapter9_CheckDeviceFormat(This, Adapter, D3DDEVTYPE_HAL, -+ Format, D3DUSAGE_RENDERTARGET, -+ D3DRTYPE_SURFACE, Format); -+ if (FAILED(hr)) { -+ TRACE("DeviceFormat not available.\n"); -+ return hr; -+ } -+ -+ if (Mode >= ADAPTER_OUTPUT.nmodes) { -+ WARN("Mode %u does not exist.\n", Mode); -+ return D3DERR_INVALIDCALL; -+ } -+ -+ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; -+ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; -+ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; -+ pMode->Format = Format; -+ -+ return D3D_OK; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_GetAdapterDisplayMode( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDISPLAYMODE *pMode ) -+{ -+ UINT Mode; -+ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { -+ WARN("Adapter %u does not exist.\n", Adapter); -+ return D3DERR_INVALIDCALL; -+ } -+ -+ Mode = ADAPTER_OUTPUT.current; -+ pMode->Width = ADAPTER_OUTPUT.modes[Mode].Width; -+ pMode->Height = ADAPTER_OUTPUT.modes[Mode].Height; -+ pMode->RefreshRate = ADAPTER_OUTPUT.modes[Mode].RefreshRate; -+ pMode->Format = ADAPTER_OUTPUT.modes[Mode].Format; -+ -+ return D3D_OK; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_CheckDeviceType( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DevType, -+ D3DFORMAT AdapterFormat, -+ D3DFORMAT BackBufferFormat, -+ BOOL bWindowed ) -+{ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } -+ return ADAPTER_PROC(CheckDeviceType, -+ DevType, AdapterFormat, BackBufferFormat, bWindowed); -+} -+ -+static HRESULT WINAPI -+d3dadapter9_CheckDeviceFormat( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DeviceType, -+ D3DFORMAT AdapterFormat, -+ DWORD Usage, -+ D3DRESOURCETYPE RType, -+ D3DFORMAT CheckFormat ) -+{ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } -+ return ADAPTER_PROC(CheckDeviceFormat, -+ DeviceType, AdapterFormat, Usage, RType, CheckFormat); -+} -+ -+static HRESULT WINAPI -+d3dadapter9_CheckDeviceMultiSampleType( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DeviceType, -+ D3DFORMAT SurfaceFormat, -+ BOOL Windowed, -+ D3DMULTISAMPLE_TYPE MultiSampleType, -+ DWORD *pQualityLevels ) -+{ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } -+ return ADAPTER_PROC(CheckDeviceMultiSampleType, DeviceType, SurfaceFormat, -+ Windowed, MultiSampleType, pQualityLevels); -+} -+ -+static HRESULT WINAPI -+d3dadapter9_CheckDepthStencilMatch( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DeviceType, -+ D3DFORMAT AdapterFormat, -+ D3DFORMAT RenderTargetFormat, -+ D3DFORMAT DepthStencilFormat ) -+{ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } -+ return ADAPTER_PROC(CheckDepthStencilMatch, DeviceType, AdapterFormat, -+ RenderTargetFormat, DepthStencilFormat); -+} -+ -+static HRESULT WINAPI -+d3dadapter9_CheckDeviceFormatConversion( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DeviceType, -+ D3DFORMAT SourceFormat, -+ D3DFORMAT TargetFormat ) -+{ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } -+ return ADAPTER_PROC(CheckDeviceFormatConversion, -+ DeviceType, SourceFormat, TargetFormat); -+} -+ -+static HRESULT WINAPI -+d3dadapter9_GetDeviceCaps( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DeviceType, -+ D3DCAPS9 *pCaps ) -+{ -+ HRESULT hr; -+ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return D3DERR_INVALIDCALL; } -+ -+ hr = ADAPTER_PROC(GetDeviceCaps, DeviceType, pCaps); -+ if (FAILED(hr)) { return hr; } -+ -+ pCaps->MasterAdapterOrdinal = This->map[Adapter].master; -+ pCaps->AdapterOrdinalInGroup = Adapter-This->map[Adapter].master; -+ pCaps->NumberOfAdaptersInGroup = ADAPTER_GROUP.noutputs; -+ -+ return hr; -+} -+ -+static HMONITOR WINAPI -+d3dadapter9_GetAdapterMonitor( struct d3dadapter9 *This, -+ UINT Adapter ) -+{ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { return (HMONITOR)0; } -+ return (HMONITOR)ADAPTER_OUTPUT.monitor; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DeviceType, -+ HWND hFocusWindow, -+ DWORD BehaviorFlags, -+ D3DPRESENT_PARAMETERS *pPresentationParameters, -+ D3DDISPLAYMODEEX *pFullscreenDisplayMode, -+ IDirect3DDevice9Ex **ppReturnedDeviceInterface ); -+ -+static HRESULT WINAPI -+d3dadapter9_CreateDevice( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DeviceType, -+ HWND hFocusWindow, -+ DWORD BehaviorFlags, -+ D3DPRESENT_PARAMETERS *pPresentationParameters, -+ IDirect3DDevice9 **ppReturnedDeviceInterface ) -+{ -+ HRESULT hr; -+ hr = d3dadapter9_CreateDeviceEx(This, Adapter, DeviceType, hFocusWindow, -+ BehaviorFlags, pPresentationParameters, -+ NULL, -+ (IDirect3DDevice9Ex **)ppReturnedDeviceInterface); -+ if (FAILED(hr)) -+ return hr; -+ return D3D_OK; -+} -+ -+static UINT WINAPI -+d3dadapter9_GetAdapterModeCountEx( struct d3dadapter9 *This, -+ UINT Adapter, -+ const D3DDISPLAYMODEFILTER *pFilter ) -+{ -+ return 1; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_EnumAdapterModesEx( struct d3dadapter9 *This, -+ UINT Adapter, -+ const D3DDISPLAYMODEFILTER *pFilter, -+ UINT Mode, -+ D3DDISPLAYMODEEX *pMode ) -+{ -+ FIXME("(%p, %u, %p, %u, %p), stub!\n", This, Adapter, pFilter, Mode, pMode); -+ return D3DERR_INVALIDCALL; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_GetAdapterDisplayModeEx( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDISPLAYMODEEX *pMode, -+ D3DDISPLAYROTATION *pRotation ) -+{ -+ FIXME("(%p, %u, %p, %p), stub!\n", This, Adapter, pMode, pRotation); -+ return D3DERR_INVALIDCALL; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_CreateDeviceEx( struct d3dadapter9 *This, -+ UINT Adapter, -+ D3DDEVTYPE DeviceType, -+ HWND hFocusWindow, -+ DWORD BehaviorFlags, -+ D3DPRESENT_PARAMETERS *pPresentationParameters, -+ D3DDISPLAYMODEEX *pFullscreenDisplayMode, -+ IDirect3DDevice9Ex **ppReturnedDeviceInterface ) -+{ -+ ID3DPresentGroup *present; -+ HRESULT hr; -+ boolean no_window_changes; -+ -+ if (Adapter >= d3dadapter9_GetAdapterCount(This)) { -+ WARN("Adapter %u does not exist.\n", Adapter); -+ return D3DERR_INVALIDCALL; -+ } -+ -+ { -+ struct adapter_group *group = &ADAPTER_GROUP; -+ unsigned nparams, ordinal; -+ -+ if (BehaviorFlags & D3DCREATE_ADAPTERGROUP_DEVICE) { -+ nparams = group->noutputs; -+ ordinal = 0; -+ } else { -+ nparams = 1; -+ ordinal = Adapter - This->map[Adapter].master; -+ } -+ no_window_changes = !!(BehaviorFlags & D3DCREATE_NOWINDOWCHANGES); -+ -+ hr = present_create_present_group(This->gdi_display, group->devname, ordinal, -+ hFocusWindow, -+ pPresentationParameters, -+ nparams, &present, This->ex, no_window_changes); -+ } -+ -+ if (FAILED(hr)) { -+ WARN("Failed to create PresentGroup.\n"); -+ return hr; -+ } -+ -+ if (This->ex) { -+ hr = ADAPTER_PROC(CreateDeviceEx, Adapter, DeviceType, hFocusWindow, -+ BehaviorFlags, pPresentationParameters, -+ pFullscreenDisplayMode, -+ (IDirect3D9Ex *)This, present, -+ ppReturnedDeviceInterface); -+ } else { /* CreateDevice on non-ex */ -+ hr = ADAPTER_PROC(CreateDevice, Adapter, DeviceType, hFocusWindow, -+ BehaviorFlags, pPresentationParameters, -+ (IDirect3D9 *)This, present, -+ (IDirect3DDevice9 **)ppReturnedDeviceInterface); -+ } -+ if (FAILED(hr)) { -+ WARN("ADAPTER_PROC failed.\n"); -+ ID3DPresentGroup_Release(present); -+ } -+ -+ return hr; -+} -+ -+static HRESULT WINAPI -+d3dadapter9_GetAdapterLUID( struct d3dadapter9 *This, -+ UINT Adapter, -+ LUID *pLUID ) -+{ -+ FIXME("(%p, %u, %p), stub!\n", This, Adapter, pLUID); -+ return D3DERR_INVALIDCALL; -+} -+ -+static struct adapter_group * -+add_group( struct d3dadapter9 *This ) -+{ -+ if (This->ngroups >= This->ngroupsalloc) { -+ void *r; -+ -+ if (This->ngroupsalloc == 0) { -+ This->ngroupsalloc = 2; -+ r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ This->ngroupsalloc*sizeof(struct adapter_group)); -+ } else { -+ This->ngroupsalloc <<= 1; -+ r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->groups, -+ This->ngroupsalloc*sizeof(struct adapter_group)); -+ } -+ -+ if (!r) { return NULL; } -+ This->groups = r; -+ } -+ -+ return &This->groups[This->ngroups++]; -+} -+ -+static void -+remove_group( struct d3dadapter9 *This ) -+{ -+ struct adapter_group *group = &This->groups[This->ngroups-1]; -+ int i; -+ -+ for (i = 0; i < group->noutputs; ++i) { -+ HeapFree(GetProcessHeap(), 0, group->outputs[i].modes); -+ } -+ HeapFree(GetProcessHeap(), 0, group->outputs); -+ -+ ZeroMemory(group, sizeof(struct adapter_group)); -+ This->ngroups--; -+} -+ -+static struct output * -+add_output( struct d3dadapter9 *This ) -+{ -+ struct adapter_group *group = &This->groups[This->ngroups-1]; -+ -+ if (group->noutputs >= group->noutputsalloc) { -+ void *r; -+ -+ if (group->noutputsalloc == 0) { -+ group->noutputsalloc = 2; -+ r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ group->noutputsalloc*sizeof(struct output)); -+ } else { -+ group->noutputsalloc <<= 1; -+ r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, group->outputs, -+ group->noutputsalloc*sizeof(struct output)); -+ } -+ -+ if (!r) { return NULL; } -+ group->outputs = r; -+ } -+ -+ return &group->outputs[group->noutputs++]; -+} -+ -+static void -+remove_output( struct d3dadapter9 *This ) -+{ -+ struct adapter_group *group = &This->groups[This->ngroups-1]; -+ struct output *out = &group->outputs[group->noutputs-1]; -+ -+ HeapFree(GetProcessHeap(), 0, out->modes); -+ -+ ZeroMemory(out, sizeof(struct output)); -+ group->noutputs--; -+} -+ -+static D3DDISPLAYMODEEX * -+add_mode( struct d3dadapter9 *This ) -+{ -+ struct adapter_group *group = &This->groups[This->ngroups-1]; -+ struct output *out = &group->outputs[group->noutputs-1]; -+ -+ if (out->nmodes >= out->nmodesalloc) { -+ void *r; -+ -+ if (out->nmodesalloc == 0) { -+ out->nmodesalloc = 8; -+ r = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX)); -+ } else { -+ out->nmodesalloc <<= 1; -+ r = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, out->modes, -+ out->nmodesalloc*sizeof(struct D3DDISPLAYMODEEX)); -+ } -+ -+ if (!r) { return NULL; } -+ out->modes = r; -+ } -+ -+ return &out->modes[out->nmodes++]; -+} -+ -+static void -+remove_mode( struct d3dadapter9 *This ) -+{ -+ struct adapter_group *group = &This->groups[This->ngroups-1]; -+ struct output *out = &group->outputs[group->noutputs-1]; -+ out->nmodes--; -+} -+ -+#ifndef DM_INTERLACED -+#define DM_INTERLACED 2 -+#endif /* DM_INTERLACED */ -+ -+static HRESULT -+fill_groups( struct d3dadapter9 *This ) -+{ -+ DISPLAY_DEVICEW dd; -+ DEVMODEW dm; -+ POINT pt; -+ HDC hdc; -+ HRESULT hr; -+ int i, j, k; -+ -+ WCHAR wdisp[] = {'D','I','S','P','L','A','Y',0}; -+ -+ ZeroMemory(&dd, sizeof(dd)); -+ ZeroMemory(&dm, sizeof(dm)); -+ dd.cb = sizeof(dd); -+ dm.dmSize = sizeof(dm); -+ -+ for (i = 0; EnumDisplayDevicesW(NULL, i, &dd, 0); ++i) { -+ struct adapter_group *group = add_group(This); -+ if (!group) { -+ ERR("Out of memory.\n"); -+ return E_OUTOFMEMORY; -+ } -+ -+ hdc = CreateDCW(wdisp, dd.DeviceName, NULL, NULL); -+ if (!hdc) { -+ remove_group(This); -+ WARN("Unable to create DC for display %d.\n", i); -+ goto end_group; -+ } -+ -+ hr = present_create_adapter9(This->gdi_display, hdc, &group->adapter); -+ DeleteDC(hdc); -+ if (FAILED(hr)) { -+ remove_group(This); -+ goto end_group; -+ } -+ -+ CopyMemory(group->devname, dd.DeviceName, sizeof(group->devname)); -+ for (j = 0; EnumDisplayDevicesW(group->devname, j, &dd, 0); ++j) { -+ struct output *out = add_output(This); -+ boolean orient = FALSE, monit = FALSE; -+ if (!out) { -+ ERR("Out of memory.\n"); -+ return E_OUTOFMEMORY; -+ } -+ -+ for (k = 0; EnumDisplaySettingsExW(dd.DeviceName, k, &dm, 0); ++k) { -+ D3DDISPLAYMODEEX *mode = add_mode(This); -+ if (!out) { -+ ERR("Out of memory.\n"); -+ return E_OUTOFMEMORY; -+ } -+ -+ mode->Size = sizeof(D3DDISPLAYMODEEX); -+ mode->Width = dm.dmPelsWidth; -+ mode->Height = dm.dmPelsHeight; -+ mode->RefreshRate = dm.dmDisplayFrequency; -+ mode->ScanLineOrdering = -+ (dm.dmDisplayFlags & DM_INTERLACED) ? -+ D3DSCANLINEORDERING_INTERLACED : -+ D3DSCANLINEORDERING_PROGRESSIVE; -+ -+ switch (dm.dmBitsPerPel) { -+ case 32: mode->Format = D3DFMT_X8R8G8B8; break; -+ case 24: mode->Format = D3DFMT_R8G8B8; break; -+ case 16: mode->Format = D3DFMT_R5G6B5; break; -+ case 8: -+ remove_mode(This); -+ goto end_mode; -+ -+ default: -+ remove_mode(This); -+ WARN("Unknown format (%u bpp) in display %d, monitor " -+ "%d, mode %d.\n", dm.dmBitsPerPel, i, j, k); -+ goto end_mode; -+ } -+ -+ if (!orient) { -+ switch (dm.dmDisplayOrientation) { -+ case DMDO_DEFAULT: -+ out->rotation = D3DDISPLAYROTATION_IDENTITY; -+ break; -+ -+ case DMDO_90: -+ out->rotation = D3DDISPLAYROTATION_90; -+ break; -+ -+ case DMDO_180: -+ out->rotation = D3DDISPLAYROTATION_180; -+ break; -+ -+ case DMDO_270: -+ out->rotation = D3DDISPLAYROTATION_270; -+ break; -+ -+ default: -+ remove_output(This); -+ WARN("Unknown display rotation in display %d, " -+ "monitor %d\n", i, j); -+ goto end_output; -+ } -+ orient = TRUE; -+ } -+ -+ if (!monit) { -+ pt.x = dm.dmPosition.x; -+ pt.y = dm.dmPosition.y; -+ out->monitor = MonitorFromPoint(pt, 0); -+ if (!out->monitor) { -+ remove_output(This); -+ WARN("Unable to get monitor handle for display %d, " -+ "monitor %d.\n", i, j); -+ goto end_output; -+ } -+ monit = TRUE; -+ } -+ -+end_mode: -+ ZeroMemory(&dm, sizeof(dm)); -+ dm.dmSize = sizeof(dm); -+ } -+ -+end_output: -+ ZeroMemory(&dd, sizeof(dd)); -+ dd.cb = sizeof(dd); -+ } -+ -+end_group: -+ ZeroMemory(&dd, sizeof(dd)); -+ dd.cb = sizeof(dd); -+ } -+ -+ return D3D_OK; -+} -+ -+static IDirect3D9ExVtbl d3dadapter9_vtable = { -+ (void *)d3dadapter9_QueryInterface, -+ (void *)d3dadapter9_AddRef, -+ (void *)d3dadapter9_Release, -+ (void *)d3dadapter9_RegisterSoftwareDevice, -+ (void *)d3dadapter9_GetAdapterCount, -+ (void *)d3dadapter9_GetAdapterIdentifier, -+ (void *)d3dadapter9_GetAdapterModeCount, -+ (void *)d3dadapter9_EnumAdapterModes, -+ (void *)d3dadapter9_GetAdapterDisplayMode, -+ (void *)d3dadapter9_CheckDeviceType, -+ (void *)d3dadapter9_CheckDeviceFormat, -+ (void *)d3dadapter9_CheckDeviceMultiSampleType, -+ (void *)d3dadapter9_CheckDepthStencilMatch, -+ (void *)d3dadapter9_CheckDeviceFormatConversion, -+ (void *)d3dadapter9_GetDeviceCaps, -+ (void *)d3dadapter9_GetAdapterMonitor, -+ (void *)d3dadapter9_CreateDevice, -+ (void *)d3dadapter9_GetAdapterModeCountEx, -+ (void *)d3dadapter9_EnumAdapterModesEx, -+ (void *)d3dadapter9_GetAdapterDisplayModeEx, -+ (void *)d3dadapter9_CreateDeviceEx, -+ (void *)d3dadapter9_GetAdapterLUID -+}; -+ -+HRESULT -+d3dadapter9_new( Display *gdi_display, -+ boolean ex, -+ IDirect3D9Ex **ppOut ) -+{ -+ struct d3dadapter9 *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ sizeof(struct d3dadapter9)); -+ HRESULT hr; -+ unsigned i, j, k; -+ -+ if (!This) { -+ ERR("Out of memory.\n"); -+ return E_OUTOFMEMORY; -+ } -+ -+ This->vtable = &d3dadapter9_vtable; -+ This->refs = 1; -+ This->ex = ex; -+ This->gdi_display = gdi_display; -+ -+ if (!has_d3dadapter(gdi_display)) { -+ ERR("Your display driver doesn't support native D3D9 adapters.\n"); -+ d3dadapter9_Release(This); -+ return D3DERR_NOTAVAILABLE; -+ } -+ -+ hr = fill_groups(This); -+ if (FAILED(hr)) { -+ d3dadapter9_Release(This); -+ return hr; -+ } -+ -+ /* map absolute adapter IDs with internal adapters */ -+ for (i = 0; i < This->ngroups; ++i) { -+ for (j = 0; j < This->groups[i].noutputs; ++j) { -+ This->nadapters++; -+ } -+ } -+ if (This->nadapters == 0) { -+ ERR("No available native adapters in system.\n"); -+ d3dadapter9_Release(This); -+ return D3DERR_NOTAVAILABLE; -+ } -+ -+ This->map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ This->nadapters*sizeof(struct adapter_map)); -+ if (!This->map) { -+ d3dadapter9_Release(This); -+ ERR("Out of memory.\n"); -+ return E_OUTOFMEMORY; -+ } -+ for (i = k = 0; i < This->ngroups; ++i) { -+ for (j = 0; j < This->groups[i].noutputs; ++j, ++k) { -+ This->map[k].master = k-j; -+ This->map[k].group = i; -+ } -+ } -+ -+ *ppOut = (IDirect3D9Ex *)This; -+ FIXME("\033[1;32m\nNative Direct3D 9 is active." -+ "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n"); -+ return D3D_OK; -+} -diff --git a/dlls/d3d9-nine/d3dadapter9.h b/dlls/d3d9-nine/d3dadapter9.h -new file mode 100644 -index 0000000..2fafdf2 ---- /dev/null -+++ b/dlls/d3d9-nine/d3dadapter9.h -@@ -0,0 +1,30 @@ -+/* -+ * D3DAdapter9 interface -+ * -+ * Copyright 2015 Patrick Rudolph -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#ifndef __WINE_D3D9ADAPTER_H -+#define __WINE_D3D9ADAPTER_H -+ -+#include <X11/Xlib.h> -+ -+void d3dadapter9_init(HINSTANCE hinst); -+void d3dadapter9_destroy(HINSTANCE hinst); -+HRESULT d3dadapter9_new(Display *gdi_display, boolean ex, IDirect3D9Ex **ppOut); -+ -+#endif /* __WINE_D3D9ADAPTER_H */ -diff --git a/dlls/d3d9-nine/dri3.c b/dlls/d3d9-nine/dri3.c -new file mode 100644 -index 0000000..d147b23 ---- /dev/null -+++ b/dlls/d3d9-nine/dri3.c -@@ -0,0 +1,1344 @@ -+/* -+ * Wine DRI3 interface -+ * -+ * Copyright 2014-2015 Axel Davy -+ * Copyright 2015 Patrick Rudolph -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+ -+#include "config.h" -+#include "wine/debug.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter); -+ -+#include <d3dadapter/d3dadapter9.h> -+#include <stdlib.h> -+#include <fcntl.h> -+#include <pthread.h> -+ -+#include "dri3.h" -+#include "winbase.h" /* for Sleep */ -+ -+#ifdef D3DADAPTER9_DRI2 -+#include <unistd.h> -+#include <sys/ioctl.h> -+#include <stdio.h> -+#include <string.h> -+ -+#define BOOL X_BOOL -+#define BYTE X_BYTE -+#define INT8 X_INT8 -+#define INT16 X_INT16 -+#define INT32 X_INT32 -+#define INT64 X_INT64 -+#include <X11/Xmd.h> -+#include <X11/Xproto.h> -+#undef BOOL -+#undef BYTE -+#undef INT8 -+#undef INT16 -+#undef INT32 -+#undef INT64 -+#undef LONG64 -+ -+#include <X11/Xlibint.h> -+#include <X11/extensions/dri2tokens.h> -+#include <X11/extensions/dri2proto.h> -+#include <X11/extensions/extutil.h> -+#define GL_GLEXT_PROTOTYPES 1 -+#define EGL_EGLEXT_PROTOTYPES 1 -+#define GL_GLEXT_LEGACY 1 -+#include <GL/gl.h> -+/* workaround gl header bug */ -+#define glBlendColor glBlendColorLEV -+#define glBlendEquation glBlendEquationLEV -+#include <GL/glext.h> -+#include <EGL/egl.h> -+#include <EGL/eglext.h> -+#include <libdrm/drm_fourcc.h> -+#include <libdrm/drm.h> -+/*GLAPI void GLAPIENTRY glFlush( void ); -+ -+GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); -+GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer); -+GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -+GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -+GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); -+GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -+GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures); -+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);*/ -+ -+typedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); -+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); -+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list); -+ -+#endif -+ -+BOOL -+DRI3CheckExtension(Display *dpy, int major, int minor) -+{ -+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy); -+ xcb_dri3_query_version_cookie_t dri3_cookie; -+ xcb_dri3_query_version_reply_t *dri3_reply; -+ xcb_generic_error_t *error; -+ const xcb_query_extension_reply_t *extension; -+ int fd; -+ -+ xcb_prefetch_extension_data(xcb_connection, &xcb_dri3_id); -+ -+ extension = xcb_get_extension_data(xcb_connection, &xcb_dri3_id); -+ if (!(extension && extension->present)) { -+ ERR("DRI3 extension is not present\n"); -+ return FALSE; -+ } -+ -+ dri3_cookie = xcb_dri3_query_version(xcb_connection, major, minor); -+ -+ dri3_reply = xcb_dri3_query_version_reply(xcb_connection, dri3_cookie, &error); -+ if (!dri3_reply) { -+ free(error); -+ ERR("Issue getting requested version of DRI3: %d,%d\n", major, minor); -+ return FALSE; -+ } -+ -+ if (!DRI3Open(dpy, DefaultScreen(dpy), &fd)) { -+ ERR("DRI3 advertised, but not working\n"); -+ return FALSE; -+ } -+ close(fd); -+ -+ TRACE("DRI3 version %d,%d found. %d %d requested\n", major, minor, (int)dri3_reply->major_version, (int)dri3_reply->minor_version); -+ free(dri3_reply); -+ -+ return TRUE; -+} -+ -+#ifdef D3DADAPTER9_DRI2 -+ -+struct DRI2priv { -+ Display *dpy; -+ EGLDisplay display; -+ EGLContext context; -+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func; -+ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func; -+ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func; -+}; -+ -+/* TODO: We don't free memory properly. When exiting, eglTerminate doesn't work well(crash), and things are freed automatically. Rely on it */ -+ -+BOOL -+DRI2FallbackInit(Display *dpy, struct DRI2priv **priv) -+{ -+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func; -+ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR_func; -+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT_func; -+ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR_func; -+ EGLDisplay display; -+ EGLint major, minor; -+ EGLConfig config; -+ EGLContext context; -+ EGLint i; -+ EGLBoolean b; -+ EGLenum current_api = 0; -+ const char *extensions; -+ EGLint config_attribs[] = { -+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, -+ EGL_NONE -+ }; -+ EGLint context_compatibility_attribs[] = { -+ EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, -+ EGL_NONE -+ }; -+ -+ current_api = eglQueryAPI(); -+ eglGetPlatformDisplayEXT_func = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT"); -+ if (!eglGetPlatformDisplayEXT_func) -+ return FALSE; -+ display = eglGetPlatformDisplayEXT_func(EGL_PLATFORM_X11_EXT, dpy, NULL); -+ if (!display) -+ return FALSE; -+ if (eglInitialize(display, &major, &minor) != EGL_TRUE) -+ goto clean_egl_display; -+ -+ extensions = eglQueryString(display, EGL_CLIENT_APIS); -+ if (!extensions || !strstr(extensions, "OpenGL")) -+ goto clean_egl_display; -+ -+ extensions = eglQueryString(display, EGL_EXTENSIONS); -+ if (!extensions || !strstr(extensions, "EGL_EXT_image_dma_buf_import") || -+ !strstr(extensions, "EGL_KHR_create_context") || -+ !strstr(extensions, "EGL_KHR_surfaceless_context") || -+ !strstr(extensions, "EGL_KHR_image_base")) -+ goto clean_egl_display; -+ -+ if (!eglChooseConfig(display, config_attribs, &config, 1, &i)) -+ goto clean_egl_display; -+ -+ b = eglBindAPI(EGL_OPENGL_API); -+ if (b == EGL_FALSE) -+ goto clean_egl_display; -+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_compatibility_attribs); -+ if (context == EGL_NO_CONTEXT) -+ goto clean_egl_display; -+ -+ glEGLImageTargetTexture2DOES_func = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES"); -+ eglCreateImageKHR_func = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR"); -+ eglDestroyImageKHR_func = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); -+ if (!eglCreateImageKHR_func || !glEGLImageTargetTexture2DOES_func || !eglDestroyImageKHR_func) { -+ ERR("eglGetProcAddress failed !"); -+ goto clean_egl_display; -+ } -+ -+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -+ -+ *priv = calloc(1, sizeof(struct DRI2priv)); -+ if (!*priv) -+ goto clean_egl; -+ (*priv)->dpy = dpy; -+ (*priv)->display = display; -+ (*priv)->context = context; -+ (*priv)->glEGLImageTargetTexture2DOES_func = glEGLImageTargetTexture2DOES_func; -+ (*priv)->eglCreateImageKHR_func = eglCreateImageKHR_func; -+ (*priv)->eglDestroyImageKHR_func = eglDestroyImageKHR_func; -+ eglBindAPI(current_api); -+ return TRUE; -+ -+clean_egl: -+clean_egl_display: -+ eglTerminate(display); -+ eglBindAPI(current_api); -+ return FALSE; -+} -+ -+/* hypothesis: at this step all textures, etc are destroyed */ -+void -+DRI2FallbackDestroy(struct DRI2priv *priv) -+{ -+ EGLenum current_api; -+ current_api = eglQueryAPI(); -+ eglBindAPI(EGL_OPENGL_API); -+ eglMakeCurrent(priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -+ eglDestroyContext(priv->display, priv->context); -+ eglTerminate(priv->display); -+ eglBindAPI(current_api); -+ free(priv); -+} -+ -+BOOL -+DRI2FallbackCheckSupport(Display *dpy) -+{ -+ struct DRI2priv *priv; -+ int fd; -+ if (!DRI2FallbackInit(dpy, &priv)) -+ return FALSE; -+ DRI2FallbackDestroy(priv); -+ if (!DRI2FallbackOpen(dpy, DefaultScreen(dpy), &fd)) -+ return FALSE; -+ close(fd); -+ return TRUE; -+} -+ -+#endif -+ -+BOOL -+PRESENTCheckExtension(Display *dpy, int major, int minor) -+{ -+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy); -+ xcb_present_query_version_cookie_t present_cookie; -+ xcb_present_query_version_reply_t *present_reply; -+ xcb_generic_error_t *error; -+ const xcb_query_extension_reply_t *extension; -+ -+ xcb_prefetch_extension_data(xcb_connection, &xcb_present_id); -+ -+ extension = xcb_get_extension_data(xcb_connection, &xcb_present_id); -+ if (!(extension && extension->present)) { -+ ERR("PRESENT extension is not present\n"); -+ return FALSE; -+ } -+ -+ present_cookie = xcb_present_query_version(xcb_connection, major, minor); -+ -+ present_reply = xcb_present_query_version_reply(xcb_connection, present_cookie, &error); -+ if (!present_reply) { -+ free(error); -+ ERR("Issue getting requested version of PRESENT: %d,%d\n", major, minor); -+ return FALSE; -+ } -+ -+ TRACE("PRESENT version %d,%d found. %d %d requested\n", major, minor, (int)present_reply->major_version, (int)present_reply->minor_version); -+ free(present_reply); -+ -+ return TRUE; -+} -+ -+BOOL -+DRI3Open(Display *dpy, int screen, int *device_fd) -+{ -+ xcb_dri3_open_cookie_t cookie; -+ xcb_dri3_open_reply_t *reply; -+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy); -+ int fd; -+ Window root = RootWindow(dpy, screen); -+ -+ cookie = xcb_dri3_open(xcb_connection, root, 0); -+ -+ reply = xcb_dri3_open_reply(xcb_connection, cookie, NULL); -+ if (!reply) -+ return FALSE; -+ -+ if (reply->nfd != 1) { -+ free(reply); -+ return FALSE; -+ } -+ -+ fd = xcb_dri3_open_reply_fds(xcb_connection, reply)[0]; -+ fcntl(fd, F_SETFD, FD_CLOEXEC); -+ -+ *device_fd = fd; -+ free(reply); -+ -+ return TRUE; -+} -+ -+#ifdef D3DADAPTER9_DRI2 -+ -+static XExtensionInfo _dri2_info_data; -+static XExtensionInfo *dri2_info = &_dri2_info_data; -+static char dri2_name[] = DRI2_NAME; -+ -+#define DRI2CheckExtension(dpy, i, val) \ -+ XextCheckExtension(dpy, i, dri2_name, val) -+ -+ -+static int -+close_display(Display *dpy, -+ XExtCodes *codes); -+static Bool -+wire_to_event(Display *dpy, -+ XEvent *re, -+ xEvent *event); -+static Status -+event_to_wire(Display *dpy, -+ XEvent *re, -+ xEvent *event); -+static int -+error( Display *dpy, -+ xError *err, -+ XExtCodes *codes, -+ int *ret_code ); -+static XExtensionHooks dri2_hooks = { -+ NULL, /* create_gc */ -+ NULL, /* copy_gc */ -+ NULL, /* flush_gc */ -+ NULL, /* free_gc */ -+ NULL, /* create_font */ -+ NULL, /* free_font */ -+ close_display, /* close_display */ -+ wire_to_event, /* wire_to_event */ -+ event_to_wire, /* event_to_wire */ -+ error, /* error */ -+ NULL, /* error_string */ -+}; -+static XEXT_GENERATE_CLOSE_DISPLAY(close_display, dri2_info); -+static XEXT_GENERATE_FIND_DISPLAY(find_display, dri2_info, -+ dri2_name, &dri2_hooks, 0, NULL); -+static Bool -+wire_to_event(Display *dpy, -+ XEvent *re, -+ xEvent *event) -+{ -+ XExtDisplayInfo *info = find_display(dpy); -+ DRI2CheckExtension(dpy, info, False); -+ TRACE("dri2 wire_to_event\n"); -+ return False; -+} -+static Status -+event_to_wire(Display *dpy, -+ XEvent *re, -+ xEvent *event) -+{ -+ XExtDisplayInfo *info = find_display(dpy); -+ DRI2CheckExtension(dpy, info, False); -+ TRACE("dri2 event_to_wire\n"); -+ return False; -+} -+static int -+error(Display *dpy, -+ xError *err, -+ XExtCodes *codes, -+ int *ret_code) -+{ -+ TRACE("dri2 error\n"); -+ return False; -+} -+ -+#define XALIGN(x) (((x) + 3) & (~3)) -+ -+static BOOL -+DRI2Connect(Display *dpy, -+ XID window, -+ unsigned driver_type, -+ char **device ) -+{ -+ XExtDisplayInfo *info = find_display(dpy); -+ xDRI2ConnectReply rep; -+ xDRI2ConnectReq *req; -+ int dev_len, driv_len; -+ char *driver; -+ -+ DRI2CheckExtension(dpy, info, False); -+ -+ LockDisplay(dpy); -+ GetReq(DRI2Connect, req); -+ req->reqType = info->codes->major_opcode; -+ req->dri2ReqType = X_DRI2Connect; -+ req->window = window; -+ req->driverType = driver_type; -+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { -+ UnlockDisplay(dpy); -+ SyncHandle(); -+ return False; -+ } -+ -+ /* check string lengths */ -+ dev_len = rep.deviceNameLength; -+ driv_len = rep.driverNameLength; -+ if (dev_len == 0 || driv_len == 0) { -+ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len)); -+ UnlockDisplay(dpy); -+ SyncHandle(); -+ return False; -+ } -+ -+ /* read out driver */ -+ driver = HeapAlloc(GetProcessHeap(), 0, driv_len + 1); -+ if (!driver) { -+ _XEatData(dpy, XALIGN(dev_len) + XALIGN(driv_len)); -+ UnlockDisplay(dpy); -+ SyncHandle(); -+ return False; -+ } -+ _XReadPad(dpy, driver, driv_len); -+ HeapFree(GetProcessHeap(), 0, driver); /* we don't need the driver */ -+ -+ /* read out device */ -+ *device = HeapAlloc(GetProcessHeap(), 0, dev_len + 1); -+ if (!*device) { -+ _XEatData(dpy, XALIGN(dev_len)); -+ UnlockDisplay(dpy); -+ SyncHandle(); -+ return False; -+ } -+ _XReadPad(dpy, *device, dev_len); -+ (*device)[dev_len] = '\0'; -+ -+ UnlockDisplay(dpy); -+ SyncHandle(); -+ -+ return True; -+} -+ -+static Bool -+DRI2Authenticate(Display *dpy, -+ XID window, -+ uint32_t token) -+{ -+ XExtDisplayInfo *info = find_display(dpy); -+ xDRI2AuthenticateReply rep; -+ xDRI2AuthenticateReq *req; -+ -+ DRI2CheckExtension(dpy, info, False); -+ -+ LockDisplay(dpy); -+ GetReq(DRI2Authenticate, req); -+ req->reqType = info->codes->major_opcode; -+ req->dri2ReqType = X_DRI2Authenticate; -+ req->window = window; -+ req->magic = token; -+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) { -+ UnlockDisplay(dpy); -+ SyncHandle(); -+ return False; -+ } -+ UnlockDisplay(dpy); -+ SyncHandle(); -+ -+ return rep.authenticated ? True : False; -+} -+ -+BOOL -+DRI2FallbackOpen(Display *dpy, int screen, int *device_fd) -+{ -+ char *device; -+ int fd; -+ Window root = RootWindow(dpy, screen); -+ drm_auth_t auth; -+ -+ if (!DRI2Connect(dpy, root, DRI2DriverDRI, &device)) -+ return FALSE; -+ -+ fd = open(device, O_RDWR); -+ HeapFree(GetProcessHeap(), 0, device); -+ if (fd < 0) -+ return FALSE; -+ -+ if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth) != 0) { -+ close(fd); -+ return FALSE; -+ } -+ -+ if (!DRI2Authenticate(dpy, root, auth.magic)) { -+ close(fd); -+ return FALSE; -+ } -+ -+ *device_fd = fd; -+ -+ return TRUE; -+} -+ -+#endif -+ -+ -+BOOL -+DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height, int stride, int depth, int bpp, Pixmap *pixmap) -+{ -+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy); -+ Window root = RootWindow(dpy, screen); -+ xcb_void_cookie_t cookie; -+ xcb_generic_error_t *error; -+ -+ cookie = xcb_dri3_pixmap_from_buffer_checked(xcb_connection, -+ (*pixmap = xcb_generate_id(xcb_connection)), -+ root, -+ 0, -+ width, height, stride, -+ depth, bpp, fd); -+ error = xcb_request_check(xcb_connection, cookie); /* performs a flush */ -+ if (error) { -+ ERR("Error using DRI3 to convert a DmaBufFd to pixmap\n"); -+ return FALSE; -+ } -+ return TRUE; -+} -+ -+BOOL -+DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height, int *stride, int *depth, int *bpp) -+{ -+ xcb_connection_t *xcb_connection = XGetXCBConnection(dpy); -+ xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie; -+ xcb_dri3_buffer_from_pixmap_reply_t *bp_reply; -+ -+ bp_cookie = xcb_dri3_buffer_from_pixmap(xcb_connection, pixmap); -+ bp_reply = xcb_dri3_buffer_from_pixmap_reply(xcb_connection, bp_cookie, NULL); -+ if (!bp_reply) -+ return FALSE; -+ *fd = xcb_dri3_buffer_from_pixmap_reply_fds(xcb_connection, bp_reply)[0]; -+ *width = bp_reply->width; -+ *height = bp_reply->height; -+ *stride = bp_reply->stride; -+ *depth = bp_reply->depth; -+ *bpp = bp_reply->depth; -+ return TRUE; -+} -+ -+struct PRESENTPriv { -+ xcb_connection_t *xcb_connection; -+ xcb_connection_t *xcb_connection_bis; /* to avoid libxcb thread bugs, use a different connection to present pixmaps */ -+ XID window; -+ uint64_t last_msc; -+ uint64_t last_target; -+ uint32_t last_serial_given; -+ xcb_special_event_t *special_event; -+ PRESENTPixmapPriv *first_present_priv; -+ int pixmap_present_pending; -+ BOOL notify_with_serial_pending; -+ pthread_mutex_t mutex_present; /* protect readind/writing present_priv things */ -+ pthread_mutex_t mutex_xcb_wait; -+ BOOL xcb_wait; -+}; -+ -+struct PRESENTPixmapPriv { -+ PRESENTpriv *present_priv; -+ Pixmap pixmap; -+ BOOL released; -+ unsigned int width; -+ unsigned int height; -+ unsigned int depth; -+ BOOL present_complete_pending; -+ uint32_t serial; -+#ifdef D3DADAPTER9_DRI2 -+ struct { -+ BOOL is_dri2; -+ struct DRI2priv *dri2_priv; -+ GLuint fbo_read; -+ GLuint fbo_write; -+ GLuint texture_read; -+ GLuint texture_write; -+ } dri2_info; -+#endif -+ BOOL last_present_was_flip; -+ PRESENTPixmapPriv *next; -+}; -+ -+static PRESENTPixmapPriv *PRESENTFindPixmapPriv(PRESENTpriv *present_priv, uint32_t serial) -+{ -+ PRESENTPixmapPriv *current = present_priv->first_present_priv; -+ -+ while (current) { -+ if (current->serial == serial) -+ return current; -+ current = current->next; -+ } -+ return NULL; -+} -+ -+static void PRESENThandle_events(PRESENTpriv *present_priv, xcb_present_generic_event_t *ge) -+{ -+ PRESENTPixmapPriv *present_pixmap_priv = NULL; -+ -+ switch (ge->evtype) { -+ case XCB_PRESENT_COMPLETE_NOTIFY: { -+ xcb_present_complete_notify_event_t *ce = (void *) ge; -+ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC) { -+ if (ce->serial) -+ present_priv->notify_with_serial_pending = FALSE; -+ free(ce); -+ return; -+ } -+ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ce->serial); -+ if (!present_pixmap_priv || ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP) { -+ ERR("FATAL ERROR: PRESENT handling failed\n"); -+ free(ce); -+ return; -+ } -+ present_pixmap_priv->present_complete_pending = FALSE; -+ switch (ce->mode) { -+ case XCB_PRESENT_COMPLETE_MODE_FLIP: -+ present_pixmap_priv->last_present_was_flip = TRUE; -+ break; -+ case XCB_PRESENT_COMPLETE_MODE_COPY: -+ present_pixmap_priv->last_present_was_flip = FALSE; -+ break; -+ } -+ present_priv->pixmap_present_pending--; -+ present_priv->last_msc = ce->msc; -+ break; -+ } -+ case XCB_PRESENT_EVENT_IDLE_NOTIFY: { -+ xcb_present_idle_notify_event_t *ie = (void *) ge; -+ present_pixmap_priv = PRESENTFindPixmapPriv(present_priv, ie->serial); -+ if (!present_pixmap_priv || present_pixmap_priv->pixmap != ie->pixmap) { -+ ERR("FATAL ERROR: PRESENT handling failed\n"); -+ free(ie); -+ return; -+ } -+ present_pixmap_priv->released = TRUE; -+ break; -+ } -+ } -+ free(ge); -+} -+ -+static void PRESENTflush_events(PRESENTpriv *present_priv, BOOL assert_no_other_thread_waiting) -+{ -+ xcb_generic_event_t *ev; -+ -+ if ((present_priv->xcb_wait && !assert_no_other_thread_waiting) || /* don't steal events to someone waiting */ -+ !present_priv->special_event) -+ return; -+ -+ while ((ev = xcb_poll_for_special_event(present_priv->xcb_connection, present_priv->special_event)) != NULL) { -+ PRESENThandle_events(present_priv, (void *) ev); -+ } -+} -+ -+static BOOL PRESENTwait_events(PRESENTpriv *present_priv, BOOL allow_other_threads) -+{ -+ xcb_generic_event_t *ev; -+ -+ if (allow_other_threads) { -+ present_priv->xcb_wait = TRUE; -+ pthread_mutex_lock(&present_priv->mutex_xcb_wait); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ } -+ ev = xcb_wait_for_special_event(present_priv->xcb_connection, present_priv->special_event); -+ if (allow_other_threads) { -+ pthread_mutex_unlock(&present_priv->mutex_xcb_wait); -+ pthread_mutex_lock(&present_priv->mutex_present); -+ present_priv->xcb_wait = FALSE; -+ } -+ if (!ev) { -+ ERR("FATAL error: xcb had an error\n"); -+ return FALSE; -+ } -+ -+ PRESENThandle_events(present_priv, (void *) ev); -+ return TRUE; -+} -+ -+static struct xcb_connection_t * -+create_xcb_connection(Display *dpy) -+{ -+ int screen_num = DefaultScreen(dpy); -+ xcb_connection_t *ret; -+ xcb_xfixes_query_version_cookie_t cookie; -+ xcb_xfixes_query_version_reply_t *rep; -+ -+ ret = xcb_connect(DisplayString(dpy), &screen_num); -+ cookie = xcb_xfixes_query_version_unchecked(ret, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); -+ rep = xcb_xfixes_query_version_reply(ret, cookie, NULL); -+ if (rep) -+ free(rep); -+ return ret; -+} -+ -+BOOL -+PRESENTInit(Display *dpy, PRESENTpriv **present_priv) -+{ -+ *present_priv = (PRESENTpriv *) calloc(1, sizeof(PRESENTpriv)); -+ if (!*present_priv) { -+ return FALSE; -+ } -+ (*present_priv)->xcb_connection = create_xcb_connection(dpy); -+ (*present_priv)->xcb_connection_bis = create_xcb_connection(dpy); -+ pthread_mutex_init(&(*present_priv)->mutex_present, NULL); -+ pthread_mutex_init(&(*present_priv)->mutex_xcb_wait, NULL); -+ return TRUE; -+} -+ -+static void PRESENTForceReleases(PRESENTpriv *present_priv) -+{ -+ PRESENTPixmapPriv *current = NULL; -+ -+ if (!present_priv->window) -+ return; -+ -+ /* There should be no other thread listening for events here. -+ * This can happen when hDestWindowOverride changes without reset. -+ * This case should never happen, but can happen in theory.*/ -+ if (present_priv->xcb_wait) { -+ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 0, 0, 0, 0); -+ xcb_flush(present_priv->xcb_connection); -+ pthread_mutex_lock(&present_priv->mutex_xcb_wait); -+ pthread_mutex_unlock(&present_priv->mutex_xcb_wait); -+ /* the problem here is that we don't have access to the event the other thread got. -+ * It is either presented event, idle event or notify event. -+ */ -+ while (present_priv->pixmap_present_pending >= 2) -+ PRESENTwait_events(present_priv, FALSE); -+ PRESENTflush_events(present_priv, TRUE); -+ /* Remaining events to come can be a pair of present/idle, -+ * or an idle, or nothing. To be sure we are after all pixmaps -+ * have been presented, add an event to the queue that can only -+ * be after the present event, then if we receive an event more, -+ * we are sure all pixmaps were presented */ -+ present_priv->notify_with_serial_pending = TRUE; -+ xcb_present_notify_msc(present_priv->xcb_connection, present_priv->window, 1, present_priv->last_target + 5, 0, 0); -+ xcb_flush(present_priv->xcb_connection); -+ while (present_priv->notify_with_serial_pending) -+ PRESENTwait_events(present_priv, FALSE); -+ /* Now we are sure we are not expecting any new event */ -+ } else { -+ while (present_priv->pixmap_present_pending) /* wait all sent pixmaps are presented */ -+ PRESENTwait_events(present_priv, FALSE); -+ PRESENTflush_events(present_priv, TRUE); /* may be remaining idle event */ -+ /* Since idle events are send with the complete events when it is not flips, -+ * we are not expecting any new event here */ -+ } -+ -+ current = present_priv->first_present_priv; -+ while (current) { -+ if (!current->released) { -+ if (!current->last_present_was_flip && !present_priv->xcb_wait) { -+ ERR("ERROR: a pixmap seems not released by PRESENT for no reason. Code bug.\n"); -+ } else { -+ /* Present the same pixmap with a non-valid part to force the copy mode and the releases */ -+ xcb_xfixes_region_t valid, update; -+ xcb_rectangle_t rect_update; -+ rect_update.x = 0; -+ rect_update.y = 0; -+ rect_update.width = 8; -+ rect_update.height = 1; -+ valid = xcb_generate_id(present_priv->xcb_connection); -+ update = xcb_generate_id(present_priv->xcb_connection); -+ xcb_xfixes_create_region(present_priv->xcb_connection, valid, 1, &rect_update); -+ xcb_xfixes_create_region(present_priv->xcb_connection, update, 1, &rect_update); -+ /* here we know the pixmap has been presented. Thus if it is on screen, -+ * the following request can only make it released by the server if it is not */ -+ xcb_present_pixmap(present_priv->xcb_connection, present_priv->window, -+ current->pixmap, 0, valid, update, 0, 0, None, None, -+ None, XCB_PRESENT_OPTION_COPY | XCB_PRESENT_OPTION_ASYNC, 0, 0, 0, 0, NULL); -+ xcb_flush(present_priv->xcb_connection); -+ PRESENTwait_events(present_priv, FALSE); /* by assumption this can only be idle event */ -+ PRESENTflush_events(present_priv, TRUE); /* Shoudln't be needed */ -+ } -+ } -+ current = current->next; -+ } -+ /* Now all pixmaps are released (possibility if xcb_wait is true that one is not aware yet), -+ * and we don't expect any new Present event to come from Xserver */ -+} -+ -+static void PRESENTFreeXcbQueue(PRESENTpriv *present_priv) -+{ -+ if (present_priv->window) { -+ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event); -+ present_priv->last_msc = 0; -+ present_priv->last_target = 0; -+ present_priv->special_event = NULL; -+ } -+} -+ -+static BOOL PRESENTPrivChangeWindow(PRESENTpriv *present_priv, XID window) -+{ -+ xcb_void_cookie_t cookie; -+ xcb_generic_error_t *error; -+ xcb_present_event_t eid; -+ -+ PRESENTForceReleases(present_priv); -+ PRESENTFreeXcbQueue(present_priv); -+ present_priv->window = window; -+ -+ if (window) { -+ cookie = xcb_present_select_input_checked(present_priv->xcb_connection, -+ (eid = xcb_generate_id(present_priv->xcb_connection)), -+ window, -+ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY| -+ XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); -+ present_priv->special_event = xcb_register_for_special_xge(present_priv->xcb_connection, -+ &xcb_present_id, -+ eid, NULL); -+ error = xcb_request_check(present_priv->xcb_connection, cookie); /* performs a flush */ -+ if (error || !present_priv->special_event) { -+ ERR("FAILED to use the X PRESENT extension. Was the destination a window ?\n"); -+ if (present_priv->special_event) -+ xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event); -+ present_priv->special_event = NULL; -+ present_priv->window = 0; -+ } -+ } -+ return (present_priv->window != 0); -+} -+ -+/* Destroy the content, except the link and the struct mem */ -+static void -+PRESENTDestroyPixmapContent(Display *dpy, PRESENTPixmapPriv *present_pixmap) -+{ -+ XFreePixmap(dpy, present_pixmap->pixmap); -+#ifdef D3DADAPTER9_DRI2 -+ if (present_pixmap->dri2_info.is_dri2) { -+ struct DRI2priv *dri2_priv = present_pixmap->dri2_info.dri2_priv; -+ EGLenum current_api; -+ current_api = eglQueryAPI(); -+ eglBindAPI(EGL_OPENGL_API); -+ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) { -+ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_read); -+ glDeleteFramebuffers(1, &present_pixmap->dri2_info.fbo_write); -+ glDeleteTextures(1, &present_pixmap->dri2_info.texture_read); -+ glDeleteTextures(1, &present_pixmap->dri2_info.texture_write); -+ } else { -+ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError()); -+ } -+ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -+ eglBindAPI(current_api); -+ } -+#endif -+} -+ -+void -+PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv) -+{ -+ PRESENTPixmapPriv *current = NULL; -+ -+ pthread_mutex_lock(&present_priv->mutex_present); -+ -+ PRESENTForceReleases(present_priv); -+ -+ current = present_priv->first_present_priv; -+ while (current) { -+ PRESENTPixmapPriv *next = current->next; -+ PRESENTDestroyPixmapContent(dpy, current); -+ free(current); -+ current = next; -+ } -+ -+ PRESENTFreeXcbQueue(present_priv); -+ -+ xcb_disconnect(present_priv->xcb_connection); -+ xcb_disconnect(present_priv->xcb_connection_bis); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ pthread_mutex_destroy(&present_priv->mutex_present); -+ pthread_mutex_destroy(&present_priv->mutex_xcb_wait); -+ -+ free(present_priv); -+} -+ -+BOOL -+PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv) -+{ -+ xcb_get_geometry_cookie_t cookie; -+ xcb_get_geometry_reply_t *reply; -+ -+ cookie = xcb_get_geometry(present_priv->xcb_connection, pixmap); -+ reply = xcb_get_geometry_reply(present_priv->xcb_connection, cookie, NULL); -+ -+ if (!reply) -+ return FALSE; -+ -+ *present_pixmap_priv = (PRESENTPixmapPriv *) calloc(1, sizeof(PRESENTPixmapPriv)); -+ if (!*present_pixmap_priv) { -+ free(reply); -+ return FALSE; -+ } -+ pthread_mutex_lock(&present_priv->mutex_present); -+ -+ (*present_pixmap_priv)->released = TRUE; -+ (*present_pixmap_priv)->pixmap = pixmap; -+ (*present_pixmap_priv)->present_priv = present_priv; -+ (*present_pixmap_priv)->next = present_priv->first_present_priv; -+ (*present_pixmap_priv)->width = reply->width; -+ (*present_pixmap_priv)->height = reply->height; -+ (*present_pixmap_priv)->depth = reply->depth; -+#ifdef D3DADAPTER9_DRI2 -+ (*present_pixmap_priv)->dri2_info.is_dri2 = FALSE; -+#endif -+ free(reply); -+ -+ present_priv->last_serial_given++; -+ (*present_pixmap_priv)->serial = present_priv->last_serial_given; -+ present_priv->first_present_priv = *present_pixmap_priv; -+ -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return TRUE; -+} -+ -+#ifdef D3DADAPTER9_DRI2 -+ -+BOOL -+DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *dri2_priv, -+ int fd, int width, int height, int stride, int depth, -+ int bpp, PRESENTPixmapPriv **present_pixmap_priv) -+{ -+ Window root = RootWindow(dri2_priv->dpy, DefaultScreen(dri2_priv->dpy)); -+ Pixmap pixmap; -+ EGLImageKHR image; -+ GLuint texture_read, texture_write, fbo_read, fbo_write; -+ EGLint attribs[] = { -+ EGL_WIDTH, 0, -+ EGL_HEIGHT, 0, -+ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888, -+ EGL_DMA_BUF_PLANE0_FD_EXT, 0, -+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, -+ EGL_DMA_BUF_PLANE0_PITCH_EXT, 0, -+ EGL_NONE -+ }; -+ EGLenum current_api; -+ int status; -+ -+ pthread_mutex_lock(&present_priv->mutex_present); -+ -+ pixmap = XCreatePixmap(dri2_priv->dpy, root, width, height, 24); -+ if (!pixmap) -+ goto fail; -+ -+ attribs[1] = width; -+ attribs[3] = height; -+ attribs[7] = fd; -+ attribs[11] = stride; -+ -+ current_api = eglQueryAPI(); -+ eglBindAPI(EGL_OPENGL_API); -+ -+ /* We bind the dma-buf to a EGLImage, then to a texture, and then to a fbo. -+ * Note that we can delete the EGLImage, but we shouldn't delete the texture, -+ * else the fbo is invalid */ -+ -+ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display, -+ EGL_NO_CONTEXT, -+ EGL_LINUX_DMA_BUF_EXT, -+ NULL, attribs); -+ -+ if (image == EGL_NO_IMAGE_KHR) -+ goto fail; -+ close(fd); -+ -+ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) { -+ glGenTextures(1, &texture_read); -+ glBindTexture(GL_TEXTURE_2D, texture_read); -+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -+ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image); -+ glGenFramebuffers(1, &fbo_read); -+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_read); -+ glFramebufferTexture2D(GL_FRAMEBUFFER, -+ GL_COLOR_ATTACHMENT0, -+ GL_TEXTURE_2D, texture_read, -+ 0); -+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER); -+ if (status != GL_FRAMEBUFFER_COMPLETE) -+ goto fail; -+ glBindTexture(GL_TEXTURE_2D, 0); -+ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image); -+ -+ /* We bind a newly created pixmap (to which we want to copy the content) -+ * to an EGLImage, then to a texture, then to a fbo. */ -+ image = dri2_priv->eglCreateImageKHR_func(dri2_priv->display, -+ dri2_priv->context, -+ EGL_NATIVE_PIXMAP_KHR, -+ (void *)pixmap, NULL); -+ if (image == EGL_NO_IMAGE_KHR) -+ goto fail; -+ -+ glGenTextures(1, &texture_write); -+ glBindTexture(GL_TEXTURE_2D, texture_write); -+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -+ dri2_priv->glEGLImageTargetTexture2DOES_func(GL_TEXTURE_2D, image); -+ glGenFramebuffers(1, &fbo_write); -+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_write); -+ glFramebufferTexture2D(GL_FRAMEBUFFER, -+ GL_COLOR_ATTACHMENT0, -+ GL_TEXTURE_2D, texture_write, -+ 0); -+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER); -+ if (status != GL_FRAMEBUFFER_COMPLETE) -+ goto fail; -+ glBindTexture(GL_TEXTURE_2D, 0); -+ dri2_priv->eglDestroyImageKHR_func(dri2_priv->display, image); -+ } else { -+ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError()); -+ } -+ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -+ -+ *present_pixmap_priv = (PRESENTPixmapPriv *) calloc(1, sizeof(PRESENTPixmapPriv)); -+ if (!*present_pixmap_priv) { -+ goto fail; -+ } -+ -+ (*present_pixmap_priv)->released = TRUE; -+ (*present_pixmap_priv)->pixmap = pixmap; -+ (*present_pixmap_priv)->present_priv = present_priv; -+ (*present_pixmap_priv)->next = present_priv->first_present_priv; -+ (*present_pixmap_priv)->width = width; -+ (*present_pixmap_priv)->height = height; -+ (*present_pixmap_priv)->depth = depth; -+ (*present_pixmap_priv)->dri2_info.is_dri2 = TRUE; -+ (*present_pixmap_priv)->dri2_info.dri2_priv = dri2_priv; -+ (*present_pixmap_priv)->dri2_info.fbo_read = fbo_read; -+ (*present_pixmap_priv)->dri2_info.fbo_write = fbo_write; -+ (*present_pixmap_priv)->dri2_info.texture_read = texture_read; -+ (*present_pixmap_priv)->dri2_info.texture_write = texture_write; -+ -+ present_priv->last_serial_given++; -+ (*present_pixmap_priv)->serial = present_priv->last_serial_given; -+ present_priv->first_present_priv = *present_pixmap_priv; -+ -+ eglBindAPI(current_api); -+ -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return TRUE; -+fail: -+ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -+ eglBindAPI(current_api); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return FALSE; -+} -+ -+#endif -+ -+BOOL -+PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv) -+{ -+ PRESENTpriv *present_priv = present_pixmap_priv->present_priv; -+ PRESENTPixmapPriv *current; -+ -+ pthread_mutex_lock(&present_priv->mutex_present); -+ -+ if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) { -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return FALSE; -+ } -+ -+ if (present_priv->first_present_priv == present_pixmap_priv) { -+ present_priv->first_present_priv = present_pixmap_priv->next; -+ goto free_priv; -+ } -+ -+ current = present_priv->first_present_priv; -+ while (current->next != present_pixmap_priv) -+ current = current->next; -+ current->next = present_pixmap_priv->next; -+free_priv: -+ PRESENTDestroyPixmapContent(dpy, present_pixmap_priv); -+ free(present_pixmap_priv); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return TRUE; -+} -+ -+BOOL -+PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv) -+{ -+ PRESENTpriv *present_priv = present_pixmap_priv->present_priv; -+ xcb_void_cookie_t cookie; -+ xcb_generic_error_t *error; -+ -+ uint32_t v = 0; -+ xcb_gcontext_t gc; -+ -+ pthread_mutex_lock(&present_priv->mutex_present); -+ -+ if (!present_priv->window) { -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return FALSE; -+ } -+ -+ xcb_create_gc(present_priv->xcb_connection, -+ (gc = xcb_generate_id(present_priv->xcb_connection)), -+ present_priv->window, -+ XCB_GC_GRAPHICS_EXPOSURES, -+ &v); -+ cookie = xcb_copy_area_checked(present_priv->xcb_connection, -+ present_priv->window, -+ present_pixmap_priv->pixmap, -+ gc, -+ 0, 0, 0, 0, -+ present_pixmap_priv->width, -+ present_pixmap_priv->height); -+ error = xcb_request_check(present_priv->xcb_connection, cookie); -+ xcb_free_gc(present_priv->xcb_connection, gc); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return (error != NULL); -+} -+ -+BOOL -+PRESENTPixmap(Display *dpy, XID window, -+ PRESENTPixmapPriv *present_pixmap_priv, D3DPRESENT_PARAMETERS *pPresentationParameters, -+ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion) -+{ -+ PRESENTpriv *present_priv = present_pixmap_priv->present_priv; -+#ifdef D3DADAPTER9_DRI2 -+ struct DRI2priv *dri2_priv = present_pixmap_priv->dri2_info.dri2_priv; -+ EGLenum current_api; -+#endif -+ xcb_void_cookie_t cookie; -+ xcb_generic_error_t *error; -+ int64_t target_msc, presentationInterval; -+ xcb_xfixes_region_t valid, update; -+ int16_t x_off, y_off; -+ uint32_t options = XCB_PRESENT_OPTION_NONE; -+ -+ pthread_mutex_lock(&present_priv->mutex_present); -+ -+ if (window != present_priv->window) -+ PRESENTPrivChangeWindow(present_priv, window); -+ -+ if (!window) { -+ ERR("ERROR: Try to Present a pixmap on a NULL window\n"); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return FALSE; -+ } -+ -+ PRESENTflush_events(present_priv, FALSE); -+ if (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) { -+ ERR("FATAL ERROR: Trying to Present a pixmap not released\n"); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return FALSE; -+ } -+#ifdef D3DADAPTER9_DRI2 -+ if (present_pixmap_priv->dri2_info.is_dri2) { -+ current_api = eglQueryAPI(); -+ eglBindAPI(EGL_OPENGL_API); -+ if(eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, dri2_priv->context)) { -+ glBindFramebuffer(GL_READ_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_read); -+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, present_pixmap_priv->dri2_info.fbo_write); -+ -+ glBlitFramebuffer(0, 0, present_pixmap_priv->width, present_pixmap_priv->height, -+ 0, 0, present_pixmap_priv->width, present_pixmap_priv->height, -+ GL_COLOR_BUFFER_BIT, GL_NEAREST); -+ glFlush(); /* Perhaps useless */ -+ } else { -+ ERR("eglMakeCurrent failed with 0x%0X\n", eglGetError()); -+ } -+ eglMakeCurrent(dri2_priv->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); -+ eglBindAPI(current_api); -+ } -+#endif -+ target_msc = present_priv->last_msc; -+ switch(pPresentationParameters->PresentationInterval) { -+ case D3DPRESENT_INTERVAL_DEFAULT: -+ case D3DPRESENT_INTERVAL_ONE: -+ presentationInterval = 1; -+ break; -+ case D3DPRESENT_INTERVAL_TWO: -+ presentationInterval = 2; -+ break; -+ case D3DPRESENT_INTERVAL_THREE: -+ presentationInterval = 3; -+ break; -+ case D3DPRESENT_INTERVAL_FOUR: -+ presentationInterval = 4; -+ break; -+ case D3DPRESENT_INTERVAL_IMMEDIATE: -+ default: -+ presentationInterval = 0; -+ options |= XCB_PRESENT_OPTION_ASYNC; -+ break; -+ } -+ target_msc += presentationInterval * (present_priv->pixmap_present_pending + 1); -+ -+ /* Note: PRESENT defines some way to do partial copy: -+ * presentproto: -+ * 'x-off' and 'y-off' define the location in the window where -+ * the 0,0 location of the pixmap will be presented. valid-area -+ * and update-area are relative to the pixmap. -+ */ -+ if (!pSourceRect && !pDestRect && !pDirtyRegion) { -+ valid = 0; -+ update = 0; -+ x_off = 0; -+ y_off = 0; -+ } else { -+ xcb_rectangle_t rect_update; -+ xcb_rectangle_t *rect_updates; -+ int i; -+ -+ rect_update.x = 0; -+ rect_update.y = 0; -+ rect_update.width = present_pixmap_priv->width; -+ rect_update.height = present_pixmap_priv->height; -+ x_off = 0; -+ y_off = 0; -+ if (pSourceRect) { -+ x_off = -pSourceRect->left; -+ y_off = -pSourceRect->top; -+ rect_update.x = pSourceRect->left; -+ rect_update.y = pSourceRect->top; -+ rect_update.width = pSourceRect->right - pSourceRect->left; -+ rect_update.height = pSourceRect->bottom - pSourceRect->top; -+ } -+ if (pDestRect) { -+ x_off += pDestRect->left; -+ y_off += pDestRect->top; -+ rect_update.width = pDestRect->right - pDestRect->left; -+ rect_update.height = pDestRect->bottom - pDestRect->top; -+ /* Note: the size of pDestRect and pSourceRect are supposed to be the same size -+ * because the driver would have done things to assure that. */ -+ } -+ valid = xcb_generate_id(present_priv->xcb_connection_bis); -+ update = xcb_generate_id(present_priv->xcb_connection_bis); -+ xcb_xfixes_create_region(present_priv->xcb_connection_bis, valid, 1, &rect_update); -+ if (pDirtyRegion && pDirtyRegion->rdh.nCount) { -+ rect_updates = (void *) calloc(pDirtyRegion->rdh.nCount, sizeof(xcb_rectangle_t)); -+ for (i = 0; i < pDirtyRegion->rdh.nCount; i++) -+ { -+ RECT rc; -+ memcpy(&rc, pDirtyRegion->Buffer + i * sizeof(RECT), sizeof(RECT)); -+ rect_update.x = rc.left; -+ rect_update.y = rc.top; -+ rect_update.width = rc.right - rc.left; -+ rect_update.height = rc.bottom - rc.top; -+ memcpy(rect_updates + i * sizeof(xcb_rectangle_t), &rect_update, sizeof(xcb_rectangle_t)); -+ } -+ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, pDirtyRegion->rdh.nCount, rect_updates); -+ free(rect_updates); -+ } else -+ xcb_xfixes_create_region(present_priv->xcb_connection_bis, update, 1, &rect_update); -+ } -+ if (pPresentationParameters->SwapEffect == D3DSWAPEFFECT_COPY) -+ options |= XCB_PRESENT_OPTION_COPY; -+ cookie = xcb_present_pixmap_checked(present_priv->xcb_connection_bis, -+ window, -+ present_pixmap_priv->pixmap, -+ present_pixmap_priv->serial, -+ valid, update, x_off, y_off, -+ None, None, None, options, -+ target_msc, 0, 0, 0, NULL); -+ error = xcb_request_check(present_priv->xcb_connection_bis, cookie); /* performs a flush */ -+ -+ if (update) -+ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, update); -+ if (valid) -+ xcb_xfixes_destroy_region(present_priv->xcb_connection_bis, valid); -+ -+ if (error) { -+ xcb_get_geometry_cookie_t cookie_geom; -+ xcb_get_geometry_reply_t *reply; -+ -+ cookie_geom = xcb_get_geometry(present_priv->xcb_connection_bis, window); -+ reply = xcb_get_geometry_reply(present_priv->xcb_connection_bis, cookie_geom, NULL); -+ -+ ERR("Error using PRESENT. Here some debug info\n"); -+ if (!reply) { -+ ERR("Error querying window info. Perhaps it doesn't exist anymore\n"); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return FALSE; -+ } -+ ERR("Pixmap: width=%d, height=%d, depth=%d\n", -+ present_pixmap_priv->width, present_pixmap_priv->height, -+ present_pixmap_priv->depth); -+ ERR("Window: width=%d, height=%d, depth=%d, x=%d, y=%d\n", -+ (int) reply->width, (int) reply->height, -+ (int) reply->depth, (int) reply->x, (int) reply->y); -+ ERR("Present parameter: PresentationInterval=%d, BackBufferCount=%d, Pending presentations=%d\n", -+ pPresentationParameters->PresentationInterval, -+ pPresentationParameters->BackBufferCount, -+ present_priv->pixmap_present_pending -+ ); -+ if (present_pixmap_priv->depth != reply->depth) -+ ERR("Depths are different. PRESENT needs the pixmap and the window have same depth\n"); -+ free(reply); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return FALSE; -+ } -+ present_priv->last_target = target_msc; -+ present_priv->pixmap_present_pending++; -+ present_pixmap_priv->present_complete_pending = TRUE; -+ present_pixmap_priv->released = FALSE; -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return TRUE; -+} -+ -+BOOL -+PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv) -+{ -+ PRESENTpriv *present_priv = present_pixmap_priv->present_priv; -+ -+ pthread_mutex_lock(&present_priv->mutex_present); -+ -+ PRESENTflush_events(present_priv, FALSE); -+ -+ while (!present_pixmap_priv->released || present_pixmap_priv->present_complete_pending) { -+ /* Note: following if should not happen because we'll never -+ * use two PRESENTWaitPixmapReleased in parallels on same window. -+ * However it would make it work in that case */ -+ if (present_priv->xcb_wait) { /* we allow only one thread to dispatch events */ -+ pthread_mutex_lock(&present_priv->mutex_xcb_wait); -+ /* here the other thread got an event but hasn't treated it yet */ -+ pthread_mutex_unlock(&present_priv->mutex_xcb_wait); -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ Sleep(10); /* Let it treat the event */ -+ pthread_mutex_lock(&present_priv->mutex_present); -+ } else if (!PRESENTwait_events(present_priv, TRUE)) { -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return FALSE; -+ } -+ } -+ pthread_mutex_unlock(&present_priv->mutex_present); -+ return TRUE; -+} -diff --git a/dlls/d3d9-nine/dri3.h b/dlls/d3d9-nine/dri3.h -new file mode 100644 -index 0000000..795c3c7 ---- /dev/null -+++ b/dlls/d3d9-nine/dri3.h -@@ -0,0 +1,106 @@ -+/* -+ * Wine X11DRV DRI3 interface -+ * -+ * Copyright 2014 Axel Davy -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#ifndef __WINE_DRI3_H -+#define __WINE_DRI3_H -+ -+#ifndef __WINE_CONFIG_H -+# error You must include config.h to use this header -+#endif -+ -+#include <X11/Xlib.h> -+#include <X11/Xutil.h> -+#include <X11/Xlib-xcb.h> -+#include <xcb/xcb.h> -+#include <xcb/dri3.h> -+#include <xcb/present.h> -+ -+BOOL -+DRI3CheckExtension(Display *dpy, int major, int minor); -+ -+#ifdef D3DADAPTER9_DRI2 -+struct DRI2priv; -+ -+BOOL -+DRI2FallbackInit(Display *dpy, struct DRI2priv **priv); -+ -+void -+DRI2FallbackDestroy(struct DRI2priv *priv); -+ -+BOOL -+DRI2FallbackCheckSupport(Display *dpy); -+#endif -+ -+BOOL -+PRESENTCheckExtension(Display *dpy, int major, int minor); -+ -+BOOL -+DRI3Open(Display *dpy, int screen, int *device_fd); -+ -+#ifdef D3DADAPTER9_DRI2 -+BOOL -+DRI2FallbackOpen(Display *dpy, int screen, int *device_fd); -+#endif -+ -+BOOL -+DRI3PixmapFromDmaBuf(Display *dpy, int screen, int fd, int width, int height, int stride, int depth, int bpp, Pixmap *pixmap); -+ -+BOOL -+DRI3DmaBufFromPixmap(Display *dpy, Pixmap pixmap, int *fd, int *width, int *height, int *stride, int *depth, int *bpp); -+ -+typedef struct PRESENTPriv PRESENTpriv; -+typedef struct PRESENTPixmapPriv PRESENTPixmapPriv; -+ -+BOOL -+PRESENTInit(Display *dpy, PRESENTpriv **present_priv); -+ -+/* will clean properly and free all PRESENTPixmapPriv associated to PRESENTpriv. -+ * PRESENTPixmapPriv should not be freed by something else. -+ * If never a PRESENTPixmapPriv has to be destroyed, -+ * please destroy the current PRESENTpriv and create a new one. -+ * This will take care than all pixmaps are released */ -+void -+PRESENTDestroy(Display *dpy, PRESENTpriv *present_priv); -+ -+BOOL -+PRESENTPixmapInit(PRESENTpriv *present_priv, Pixmap pixmap, PRESENTPixmapPriv **present_pixmap_priv); -+ -+#ifdef D3DADAPTER9_DRI2 -+BOOL -+DRI2FallbackPRESENTPixmap(PRESENTpriv *present_priv, struct DRI2priv *priv, -+ int fd, int width, int height, int stride, int depth, -+ int bpp, PRESENTPixmapPriv **present_pixmap_priv); -+#endif -+ -+BOOL -+PRESENTTryFreePixmap(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv); -+ -+BOOL -+PRESENTHelperCopyFront(Display *dpy, PRESENTPixmapPriv *present_pixmap_priv); -+ -+BOOL -+PRESENTPixmap(Display *dpy, XID window, -+ PRESENTPixmapPriv *present_pixmap_priv, D3DPRESENT_PARAMETERS *pPresentationParameters, -+ const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion); -+ -+BOOL -+PRESENTWaitPixmapReleased(PRESENTPixmapPriv *present_pixmap_priv); -+ -+#endif /* __WINE_DRI3_H */ -diff --git a/dlls/d3d9-nine/libd3d9-nine.def b/dlls/d3d9-nine/libd3d9-nine.def -new file mode 100644 -index 0000000..4f41fcb ---- /dev/null -+++ b/dlls/d3d9-nine/libd3d9-nine.def -@@ -0,0 +1,16 @@ -+; File generated automatically from ./dlls/d3d9-nine/d3d9-nine.spec; do not edit! -+ -+LIBRARY d3d9-nine.dll -+ -+EXPORTS -+ Direct3DShaderValidatorCreate9@0 @1 -+ D3DPERF_BeginEvent@8 @4 -+ D3DPERF_EndEvent@0 @5 -+ D3DPERF_GetStatus@0 @6 -+ D3DPERF_QueryRepeatFrame@0 @7 -+ D3DPERF_SetMarker@8 @8 -+ D3DPERF_SetOptions@4 @9 -+ D3DPERF_SetRegion@8 @10 -+ DebugSetMute@0 @12 -+ Direct3DCreate9@4 @13 -+ Direct3DCreate9Ex@8 @14 -diff --git a/dlls/d3d9-nine/present.c b/dlls/d3d9-nine/present.c -new file mode 100644 -index 0000000..931c784 ---- /dev/null -+++ b/dlls/d3d9-nine/present.c -@@ -0,0 +1,1333 @@ -+/* -+ * Wine ID3DAdapter9 support functions -+ * -+ * Copyright 2013 Joakim Sindholt -+ * Christoph Bumiller -+ * Copyright 2014 Tiziano Bacocco -+ * David Heidelberger -+ * Copyright 2014-2015 Axel Davy -+ * Copyright 2015 Patrick Rudolph -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#include "config.h" -+#include "wine/port.h" -+#include "wine/debug.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(d3dadapter); -+ -+#include <d3dadapter/d3dadapter9.h> -+#include <d3dadapter/drm.h> -+#include <libdrm/drm.h> -+#include <errno.h> -+#include <fcntl.h> -+ -+#include "dri3.h" -+#include "wine/library.h" -+#include "wine/unicode.h" -+ -+#ifndef D3DPRESENT_DONOTWAIT -+#define D3DPRESENT_DONOTWAIT 0x00000001 -+#endif -+ -+#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR 1 -+#ifdef ID3DPresent_GetWindowOccluded -+#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 1 -+#else -+#define WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR 0 -+#endif -+ -+static const struct D3DAdapter9DRM *d3d9_drm = NULL; -+#ifdef D3DADAPTER9_DRI2 -+static int is_dri2_fallback = 0; -+#endif -+ -+#define X11DRV_ESCAPE 6789 -+enum x11drv_escape_codes -+{ -+ X11DRV_SET_DRAWABLE, /* set current drawable for a DC */ -+ X11DRV_GET_DRAWABLE, /* get current drawable for a DC */ -+ X11DRV_START_EXPOSURES, /* start graphics exposures */ -+ X11DRV_END_EXPOSURES, /* end graphics exposures */ -+ X11DRV_FLUSH_GL_DRAWABLE /* flush changes made to the gl drawable */ -+}; -+ -+struct x11drv_escape_get_drawable -+{ -+ enum x11drv_escape_codes code; /* escape code (X11DRV_GET_DRAWABLE) */ -+ Drawable drawable; /* X drawable */ -+ Drawable gl_drawable; /* GL drawable */ -+ int pixel_format; /* internal GL pixel format */ -+ RECT dc_rect; /* DC rectangle relative to drawable */ -+}; -+ -+static XContext d3d_hwnd_context; -+static CRITICAL_SECTION context_section; -+static CRITICAL_SECTION_DEBUG critsect_debug = -+{ -+ 0, 0, &context_section, -+ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, -+ 0, 0, { (DWORD_PTR)(__FILE__ ": context_section") } -+}; -+static CRITICAL_SECTION context_section = { &critsect_debug, -1, 0, 0, 0, 0 }; -+ -+const GUID IID_ID3DPresent = { 0x77D60E80, 0xF1E6, 0x11DF, { 0x9E, 0x39, 0x95, 0x0C, 0xDF, 0xD7, 0x20, 0x85 } }; -+const GUID IID_ID3DPresentGroup = { 0xB9C3016E, 0xF32A, 0x11DF, { 0x9C, 0x18, 0x92, 0xEA, 0xDE, 0xD7, 0x20, 0x85 } }; -+ -+struct d3d_drawable -+{ -+ Drawable drawable; /* X11 drawable */ -+ RECT dc_rect; /* rect relative to the X11 drawable */ -+ HDC hdc; -+ HWND wnd; /* HWND (for convenience) */ -+}; -+ -+#ifdef ID3DPresent_GetWindowOccluded -+static HHOOK hhook; -+ -+struct d3d_wnd_hooks -+{ -+ HWND focus_wnd; -+ struct DRI3Present *present; -+ struct d3d_wnd_hooks *prev; -+ struct d3d_wnd_hooks *next; -+}; -+ -+static HRESULT dri3_present_unregister_window_hook( struct DRI3Present *This ); -+static HRESULT dri3_present_register_window_hook( struct DRI3Present *This ); -+ -+static struct d3d_wnd_hooks d3d_hooks; -+#endif -+ -+struct DRI3Present -+{ -+ /* COM vtable */ -+ void *vtable; -+ /* IUnknown reference count */ -+ LONG refs; -+ -+ D3DPRESENT_PARAMETERS params; -+ HWND focus_wnd; -+ PRESENTpriv *present_priv; -+#ifdef D3DADAPTER9_DRI2 -+ struct DRI2priv *dri2_priv; -+#endif -+ -+ WCHAR devname[32]; -+ HCURSOR hCursor; -+ -+ DEVMODEW initial_mode; -+ BOOL device_needs_reset; -+ BOOL occluded; -+ Display *gdi_display; -+ struct d3d_drawable *d3d; -+ boolean ex; -+ boolean no_window_changes; -+ boolean mode_changed; -+ long style; -+ long style_ex; -+ boolean drop_wnd_messages; -+}; -+ -+struct D3DWindowBuffer -+{ -+ PRESENTPixmapPriv *present_pixmap_priv; -+}; -+ -+static void -+free_d3dadapter_drawable(struct d3d_drawable *d3d) -+{ -+ ReleaseDC(d3d->wnd, d3d->hdc); -+ HeapFree(GetProcessHeap(), 0, d3d); -+} -+ -+void -+destroy_d3dadapter_drawable(Display *gdi_display, HWND hwnd) -+{ -+ struct d3d_drawable *d3d; -+ -+ EnterCriticalSection(&context_section); -+ if (!XFindContext(gdi_display, (XID)hwnd, -+ d3d_hwnd_context, (char **)&d3d)) { -+ XDeleteContext(gdi_display, (XID)hwnd, d3d_hwnd_context); -+ free_d3dadapter_drawable(d3d); -+ } -+ LeaveCriticalSection(&context_section); -+} -+ -+static struct d3d_drawable * -+create_d3dadapter_drawable(HWND hwnd) -+{ -+ struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE }; -+ struct d3d_drawable *d3d; -+ -+ d3d = HeapAlloc(GetProcessHeap(), 0, sizeof(*d3d)); -+ if (!d3d) { -+ ERR("Couldn't allocate d3d_drawable.\n"); -+ return NULL; -+ } -+ -+ d3d->hdc = GetDCEx(hwnd, 0, DCX_CACHE | DCX_CLIPSIBLINGS); -+ if (ExtEscape(d3d->hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc, -+ sizeof(extesc), (LPSTR)&extesc) <= 0) { -+ ERR("Unexpected error in X Drawable lookup (hwnd=%p, hdc=%p)\n", -+ hwnd, d3d->hdc); -+ ReleaseDC(hwnd, d3d->hdc); -+ HeapFree(GetProcessHeap(), 0, d3d); -+ return NULL; -+ } -+ -+ d3d->drawable = extesc.drawable; -+ d3d->wnd = hwnd; -+ d3d->dc_rect = extesc.dc_rect; -+ -+ return d3d; -+} -+ -+static struct d3d_drawable * -+get_d3d_drawable(Display *gdi_display, HWND hwnd) -+{ -+ struct d3d_drawable *d3d, *race; -+ -+ EnterCriticalSection(&context_section); -+ if (!XFindContext(gdi_display, (XID)hwnd, -+ d3d_hwnd_context, (char **)&d3d)) { -+ struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE }; -+ -+ /* check if the window has moved since last we used it */ -+ if (ExtEscape(d3d->hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc, -+ sizeof(extesc), (LPSTR)&extesc) <= 0) { -+ WARN("Window update check failed (hwnd=%p, hdc=%p)\n", -+ hwnd, d3d->hdc); -+ } -+ -+ if (!EqualRect(&d3d->dc_rect, &extesc.dc_rect)) -+ d3d->dc_rect = extesc.dc_rect; -+ -+ return d3d; -+ } -+ LeaveCriticalSection(&context_section); -+ -+ TRACE("No d3d_drawable attached to hwnd %p, creating one.\n", hwnd); -+ -+ d3d = create_d3dadapter_drawable(hwnd); -+ if (!d3d) { return NULL; } -+ -+ EnterCriticalSection(&context_section); -+ if (!XFindContext(gdi_display, (XID)hwnd, -+ d3d_hwnd_context, (char **)&race)) { -+ /* apparently someone beat us to creating this d3d drawable. Let's not -+ waste more time with X11 calls and just use theirs instead. */ -+ free_d3dadapter_drawable(d3d); -+ return race; -+ } -+ XSaveContext(gdi_display, (XID)hwnd, d3d_hwnd_context, (char *)d3d); -+ return d3d; -+} -+ -+static void -+release_d3d_drawable(struct d3d_drawable *d3d) -+{ -+ if (d3d) { LeaveCriticalSection(&context_section); } -+} -+ -+static ULONG WINAPI -+DRI3Present_AddRef( struct DRI3Present *This ) -+{ -+ ULONG refs = InterlockedIncrement(&This->refs); -+ TRACE("%p increasing refcount to %u.\n", This, refs); -+ return refs; -+} -+ -+static ULONG WINAPI -+DRI3Present_Release( struct DRI3Present *This ) -+{ -+ ULONG refs = InterlockedDecrement(&This->refs); -+ TRACE("%p decreasing refcount to %u.\n", This, refs); -+ if (refs == 0) { -+ /* dtor */ -+#ifdef ID3DPresent_GetWindowOccluded -+ dri3_present_unregister_window_hook(This); -+#endif -+ if (This->d3d) -+ destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd); -+ ChangeDisplaySettingsExW(This->devname, &(This->initial_mode), 0, CDS_FULLSCREEN, NULL); -+ -+ PRESENTDestroy(This->gdi_display, This->present_priv); -+#ifdef D3DADAPTER9_DRI2 -+ if (is_dri2_fallback) -+ DRI2FallbackDestroy(This->dri2_priv); -+#endif -+ HeapFree(GetProcessHeap(), 0, This); -+ } -+ return refs; -+} -+ -+static HRESULT WINAPI -+DRI3Present_QueryInterface( struct DRI3Present *This, -+ REFIID riid, -+ void **ppvObject ) -+{ -+ if (!ppvObject) { return E_POINTER; } -+ -+ if (IsEqualGUID(&IID_ID3DPresent, riid) || -+ IsEqualGUID(&IID_IUnknown, riid)) { -+ *ppvObject = This; -+ DRI3Present_AddRef(This); -+ return S_OK; -+ } -+ -+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); -+ *ppvObject = NULL; -+ -+ return E_NOINTERFACE; -+} -+ -+static HRESULT -+DRI3Present_ChangePresentParameters( struct DRI3Present *This, -+ D3DPRESENT_PARAMETERS *params); -+ -+static HRESULT WINAPI -+DRI3Present_SetPresentParameters( struct DRI3Present *This, -+ D3DPRESENT_PARAMETERS *pPresentationParameters, -+ D3DDISPLAYMODEEX *pFullscreenDisplayMode ) -+{ -+ if (pFullscreenDisplayMode) -+ ERR("Ignoring pFullscreenDisplayMode\n"); -+ return DRI3Present_ChangePresentParameters(This, pPresentationParameters); -+} -+ -+static HRESULT WINAPI -+DRI3Present_D3DWindowBufferFromDmaBuf( struct DRI3Present *This, -+ int dmaBufFd, -+ int width, -+ int height, -+ int stride, -+ int depth, -+ int bpp, -+ struct D3DWindowBuffer **out) -+{ -+ Pixmap pixmap; -+ -+#ifdef D3DADAPTER9_DRI2 -+ if (is_dri2_fallback) { -+ *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ sizeof(struct D3DWindowBuffer)); -+ DRI2FallbackPRESENTPixmap(This->present_priv, This->dri2_priv, -+ dmaBufFd, width, height, stride, depth, -+ bpp, -+ &((*out)->present_pixmap_priv)); -+ return D3D_OK; -+ } -+#endif -+ if (!DRI3PixmapFromDmaBuf(This->gdi_display, DefaultScreen(This->gdi_display), -+ dmaBufFd, width, height, stride, depth, -+ bpp, &pixmap )) -+ return D3DERR_DRIVERINTERNALERROR; -+ -+ *out = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ sizeof(struct D3DWindowBuffer)); -+ PRESENTPixmapInit(This->present_priv, pixmap, &((*out)->present_pixmap_priv)); -+ return D3D_OK; -+} -+ -+static HRESULT WINAPI -+DRI3Present_DestroyD3DWindowBuffer( struct DRI3Present *This, -+ struct D3DWindowBuffer *buffer ) -+{ -+ /* the pixmap is managed by the PRESENT backend. -+ * But if it can delete it right away, we may have -+ * better performance */ -+ PRESENTTryFreePixmap(This->gdi_display, buffer->present_pixmap_priv); -+ HeapFree(GetProcessHeap(), 0, buffer); -+ return D3D_OK; -+} -+ -+static HRESULT WINAPI -+DRI3Present_WaitBufferReleased( struct DRI3Present *This, -+ struct D3DWindowBuffer *buffer) -+{ -+ PRESENTWaitPixmapReleased(buffer->present_pixmap_priv); -+ return D3D_OK; -+} -+ -+static HRESULT WINAPI -+DRI3Present_FrontBufferCopy( struct DRI3Present *This, -+ struct D3DWindowBuffer *buffer ) -+{ -+#ifdef D3DADAPTER9_DRI2 -+ if (is_dri2_fallback) -+ return D3DERR_DRIVERINTERNALERROR; -+#endif -+ /* TODO: use dc_rect */ -+ if (PRESENTHelperCopyFront(This->gdi_display, buffer->present_pixmap_priv)) -+ return D3D_OK; -+ else -+ return D3DERR_DRIVERINTERNALERROR; -+} -+ -+static HRESULT WINAPI -+DRI3Present_PresentBuffer( struct DRI3Present *This, -+ struct D3DWindowBuffer *buffer, -+ HWND hWndOverride, -+ const RECT *pSourceRect, -+ const RECT *pDestRect, -+ const RGNDATA *pDirtyRegion, -+ DWORD Flags ) -+{ -+ struct d3d_drawable *d3d; -+ RECT dest_translate; -+ -+ if (hWndOverride) { -+ d3d = get_d3d_drawable(This->gdi_display, hWndOverride); -+ } else if (This->params.hDeviceWindow) { -+ d3d = get_d3d_drawable(This->gdi_display, This->params.hDeviceWindow); -+ } else { -+ d3d = get_d3d_drawable(This->gdi_display, This->focus_wnd); -+ } -+ if (!d3d) { return D3DERR_DRIVERINTERNALERROR; } -+ -+ /* TODO: should we use a list here instead ? */ -+ if (This->d3d && (This->d3d->wnd != d3d->wnd)) { -+ destroy_d3dadapter_drawable(This->gdi_display, This->d3d->wnd); -+ } -+ This->d3d = d3d; -+ -+ if (d3d->dc_rect.top != 0 && -+ d3d->dc_rect.left != 0) { -+ if (!pDestRect) -+ pDestRect = (const RECT *) &(d3d->dc_rect); -+ else { -+ dest_translate.top = pDestRect->top + d3d->dc_rect.top; -+ dest_translate.left = pDestRect->left + d3d->dc_rect.left; -+ dest_translate.bottom = pDestRect->bottom + d3d->dc_rect.bottom; -+ dest_translate.right = pDestRect->right + d3d->dc_rect.right; -+ pDestRect = (const RECT *) &dest_translate; -+ } -+ } -+ -+ if (!PRESENTPixmap(This->gdi_display, d3d->drawable, buffer->present_pixmap_priv, -+ &This->params, pSourceRect, pDestRect, pDirtyRegion)) -+ return D3DERR_DRIVERINTERNALERROR; -+ -+ release_d3d_drawable(d3d); -+ -+ return D3D_OK; -+} -+ -+static HRESULT WINAPI -+DRI3Present_GetRasterStatus( struct DRI3Present *This, -+ D3DRASTER_STATUS *pRasterStatus ) -+{ -+ FIXME("(%p, %p), stub!\n", This, pRasterStatus); -+ return D3DERR_INVALIDCALL; -+} -+ -+static HRESULT WINAPI -+DRI3Present_GetDisplayMode( struct DRI3Present *This, -+ D3DDISPLAYMODEEX *pMode, -+ D3DDISPLAYROTATION *pRotation ) -+{ -+ DEVMODEW dm; -+ -+ ZeroMemory(&dm, sizeof(dm)); -+ dm.dmSize = sizeof(dm); -+ -+ EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &dm, 0); -+ pMode->Width = dm.dmPelsWidth; -+ pMode->Height = dm.dmPelsHeight; -+ pMode->RefreshRate = dm.dmDisplayFrequency; -+ pMode->ScanLineOrdering = (dm.dmDisplayFlags & DM_INTERLACED) ? -+ D3DSCANLINEORDERING_INTERLACED : -+ D3DSCANLINEORDERING_PROGRESSIVE; -+ -+ /* XXX This is called "guessing" */ -+ switch (dm.dmBitsPerPel) { -+ case 32: pMode->Format = D3DFMT_X8R8G8B8; break; -+ case 24: pMode->Format = D3DFMT_R8G8B8; break; -+ case 16: pMode->Format = D3DFMT_R5G6B5; break; -+ default: -+ WARN("Unknown display format with %u bpp.\n", dm.dmBitsPerPel); -+ pMode->Format = D3DFMT_UNKNOWN; -+ } -+ -+ switch (dm.dmDisplayOrientation) { -+ case DMDO_DEFAULT: *pRotation = D3DDISPLAYROTATION_IDENTITY; break; -+ case DMDO_90: *pRotation = D3DDISPLAYROTATION_90; break; -+ case DMDO_180: *pRotation = D3DDISPLAYROTATION_180; break; -+ case DMDO_270: *pRotation = D3DDISPLAYROTATION_270; break; -+ default: -+ WARN("Unknown display rotation %u.\n", dm.dmDisplayOrientation); -+ *pRotation = D3DDISPLAYROTATION_IDENTITY; -+ } -+ -+ return D3D_OK; -+} -+ -+static HRESULT WINAPI -+DRI3Present_GetPresentStats( struct DRI3Present *This, -+ D3DPRESENTSTATS *pStats ) -+{ -+ FIXME("(%p, %p), stub!\n", This, pStats); -+ return D3DERR_INVALIDCALL; -+} -+ -+static HRESULT WINAPI -+DRI3Present_GetCursorPos( struct DRI3Present *This, -+ POINT *pPoint ) -+{ -+ BOOL ok; -+ HWND draw_window; -+ -+ if (!pPoint) -+ return D3DERR_INVALIDCALL; -+ -+ draw_window = This->params.hDeviceWindow ? -+ This->params.hDeviceWindow : This->focus_wnd; -+ -+ ok = GetCursorPos(pPoint); -+ ok = ok && ScreenToClient(draw_window, pPoint); -+ return ok ? S_OK : D3DERR_DRIVERINTERNALERROR; -+} -+ -+static HRESULT WINAPI -+DRI3Present_SetCursorPos( struct DRI3Present *This, -+ POINT *pPoint ) -+{ -+ BOOL ok; -+ POINT real_pos; -+ -+ if (!pPoint) -+ return D3DERR_INVALIDCALL; -+ -+ ok = SetCursorPos(pPoint->x, pPoint->y); -+ if (!ok) -+ goto error; -+ -+ ok = GetCursorPos(&real_pos); -+ if (!ok || real_pos.x != pPoint->x || real_pos.y != pPoint->y) -+ goto error; -+ -+ return D3D_OK; -+ -+error: -+ SetCursor(NULL); /* Hide cursor rather than put wrong pos */ -+ return D3DERR_DRIVERINTERNALERROR; -+} -+ -+ -+/* Note: assuming 32x32 cursor */ -+static HRESULT WINAPI -+DRI3Present_SetCursor( struct DRI3Present *This, -+ void *pBitmap, -+ POINT *pHotspot, -+ BOOL bShow ) -+{ -+ if (pBitmap) { -+ ICONINFO info; -+ HCURSOR cursor; -+ -+ DWORD mask[32]; -+ memset(mask, ~0, sizeof(mask)); -+ -+ if (!pHotspot) -+ return D3DERR_INVALIDCALL; -+ info.fIcon = FALSE; -+ info.xHotspot = pHotspot->x; -+ info.yHotspot = pHotspot->y; -+ info.hbmMask = CreateBitmap(32, 32, 1, 1, mask); -+ info.hbmColor = CreateBitmap(32, 32, 1, 32, pBitmap); -+ -+ cursor = CreateIconIndirect(&info); -+ if (info.hbmMask) DeleteObject(info.hbmMask); -+ if (info.hbmColor) DeleteObject(info.hbmColor); -+ if (cursor) -+ DestroyCursor(This->hCursor); -+ This->hCursor = cursor; -+ } -+ SetCursor(bShow ? This->hCursor : NULL); -+ -+ return D3D_OK; -+} -+ -+static HRESULT WINAPI -+DRI3Present_SetGammaRamp( struct DRI3Present *This, -+ const D3DGAMMARAMP *pRamp, -+ HWND hWndOverride ) -+{ -+ HWND hWnd = hWndOverride ? hWndOverride : This->focus_wnd; -+ HDC hdc; -+ BOOL ok; -+ if (!pRamp) { -+ return D3DERR_INVALIDCALL; -+ } -+ hdc = GetDC(hWnd); -+ ok = SetDeviceGammaRamp(hdc, (void *)pRamp); -+ ReleaseDC(hWnd, hdc); -+ return ok ? D3D_OK : D3DERR_DRIVERINTERNALERROR; -+} -+ -+static HRESULT WINAPI -+DRI3Present_GetWindowInfo( struct DRI3Present *This, -+ HWND hWnd, -+ int *width, int *height, int *depth ) -+{ -+ HRESULT hr; -+ RECT pRect; -+ -+ if (!hWnd) -+ hWnd = This->focus_wnd; -+ hr = GetClientRect(hWnd, &pRect); -+ if (!hr) -+ return D3DERR_INVALIDCALL; -+ *width = pRect.right - pRect.left; -+ *height = pRect.bottom - pRect.top; -+ *depth = 24; //TODO -+ return D3D_OK; -+} -+ -+static LONG fullscreen_style(LONG style) -+{ -+ /* Make sure the window is managed, otherwise we won't get keyboard input. */ -+ style |= WS_POPUP | WS_SYSMENU; -+ style &= ~(WS_CAPTION | WS_THICKFRAME); -+ -+ return style; -+} -+ -+static LONG fullscreen_exstyle(LONG exstyle) -+{ -+ /* Filter out window decorations. */ -+ exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE); -+ -+ return exstyle; -+} -+ -+static HRESULT -+DRI3Present_ChangeDisplaySettingsIfNeccessary( struct DRI3Present *This, DEVMODEW *new_mode ) { -+ DEVMODEW current_mode; -+ LONG hr; -+ -+ ZeroMemory(¤t_mode, sizeof(DEVMODEW)); -+ /* Only change the mode if necessary. */ -+ if (!EnumDisplaySettingsW(This->devname, ENUM_CURRENT_SETTINGS, ¤t_mode)) -+ { -+ ERR("Failed to get current display mode.\n"); -+ } else if (current_mode.dmPelsWidth != new_mode->dmPelsWidth -+ || current_mode.dmPelsHeight != new_mode->dmPelsHeight -+ || (current_mode.dmDisplayFrequency != new_mode->dmDisplayFrequency -+ && (new_mode->dmFields & DM_DISPLAYFREQUENCY))) -+ { -+ hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL); -+ if (hr != DISP_CHANGE_SUCCESSFUL) { -+ /* try again without display RefreshRate */ -+ if (new_mode->dmFields & DM_DISPLAYFREQUENCY) { -+ new_mode->dmFields &= ~DM_DISPLAYFREQUENCY; -+ new_mode->dmDisplayFrequency = 0; -+ hr = ChangeDisplaySettingsExW(This->devname, new_mode, 0, CDS_FULLSCREEN, NULL); -+ if (hr != DISP_CHANGE_SUCCESSFUL) { -+ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr); -+ return D3DERR_INVALIDCALL; -+ } -+ } else { -+ ERR("ChangeDisplaySettingsExW failed with 0x%08X\n", hr); -+ return D3DERR_INVALIDCALL; -+ } -+ } -+ } -+ return D3D_OK; -+} -+ -+#ifdef ID3DPresent_GetWindowOccluded -+static struct d3d_wnd_hooks *get_last_hook(void) { -+ struct d3d_wnd_hooks *hook = &d3d_hooks; -+ while (hook->next) { -+ hook = hook->next; -+ } -+ return hook; -+} -+ -+LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) -+{ -+ struct d3d_wnd_hooks *hook = &d3d_hooks; -+ boolean drop_wnd_messages; -+ -+ if (nCode < 0) { -+ return CallNextHookEx(hhook, nCode, wParam, lParam); -+ } -+ -+ if (lParam) { -+ CWPSTRUCT wndprocparams = *((CWPSTRUCT*)lParam); -+ while (hook->next) { -+ hook = hook->next; -+ -+ /* skip messages for other hwnds */ -+ if (hook->focus_wnd != wndprocparams.hwnd) -+ continue; -+ if (!hook->present) -+ continue; -+ -+ switch (wndprocparams.message) { -+ case WM_ACTIVATEAPP: -+ if (hook->present->drop_wnd_messages) -+ return -1; -+ -+ drop_wnd_messages = hook->present->drop_wnd_messages; -+ hook->present->drop_wnd_messages = TRUE; -+ if (wndprocparams.wParam == WA_INACTIVE) { -+ hook->present->occluded = TRUE; -+ -+ DRI3Present_ChangeDisplaySettingsIfNeccessary(hook->present, &(hook->present->initial_mode)); -+ -+ if (!hook->present->no_window_changes && -+ IsWindowVisible(hook->present->params.hDeviceWindow)) -+ ShowWindow(hook->present->params.hDeviceWindow, SW_MINIMIZE); -+ } else { -+ hook->present->device_needs_reset |= hook->present->occluded; -+ hook->present->occluded = FALSE; -+ -+ if (!hook->present->no_window_changes) { -+ /* restore window */ -+ SetWindowPos(hook->present->params.hDeviceWindow, NULL, 0, 0, -+ hook->present->params.BackBufferWidth, hook->present->params.BackBufferHeight, -+ SWP_NOACTIVATE | SWP_NOZORDER); -+ } -+ -+ if (hook->present->ex) { -+ DEVMODEW new_mode; -+ -+ ZeroMemory(&new_mode, sizeof(DEVMODEW)); -+ new_mode.dmPelsWidth = hook->present->params.BackBufferWidth; -+ new_mode.dmPelsHeight = hook->present->params.BackBufferHeight; -+ new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; -+ if (hook->present->params.FullScreen_RefreshRateInHz) { -+ new_mode.dmFields |= DM_DISPLAYFREQUENCY; -+ new_mode.dmDisplayFrequency = hook->present->params.FullScreen_RefreshRateInHz; -+ } -+ new_mode.dmSize = sizeof(DEVMODEW); -+ DRI3Present_ChangeDisplaySettingsIfNeccessary(hook->present, &new_mode); -+ } -+ } -+ hook->present->drop_wnd_messages = drop_wnd_messages; -+ break; -+ case WM_DISPLAYCHANGE: -+ hook->present->mode_changed = TRUE; -+ hook->present->device_needs_reset = TRUE; -+ break; -+ /* TODO: handle other window messages here */ -+ default: -+ break; -+ } -+ } -+ } -+ -+ return CallNextHookEx(hhook, nCode, wParam, lParam); -+} -+ -+static HRESULT dri3_present_register_window_hook( struct DRI3Present *This ) { -+ struct d3d_wnd_hooks *lasthook; -+ struct d3d_wnd_hooks *hook = &d3d_hooks; -+ -+ HWND hWnd = This->focus_wnd; -+ -+ /* let's see if already hooked */ -+ while (hook->next) { -+ hook = hook->next; -+ if (hook->focus_wnd == hWnd && hook->present == This) -+ return D3DERR_INVALIDCALL; -+ } -+ /* create single WindowsHook in this process */ -+ if (!hhook) { -+ // TODO: do we need to handle different threadIDs ? -+ DWORD threadID = GetWindowThreadProcessId(hWnd, NULL); -+ hhook = SetWindowsHookExW(WH_CALLWNDPROC, HookCallback, NULL, threadID); -+ if (!hhook) { -+ ERR("SetWindowsHookEx failed with 0x%08x\n", GetLastError()); -+ return D3DERR_DRIVERINTERNALERROR; -+ } -+ } -+ lasthook = get_last_hook(); -+ hook = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ sizeof(struct d3d_wnd_hooks)); -+ if (!hook) -+ return E_OUTOFMEMORY; -+ /* add window hwnd to list */ -+ lasthook->next = hook; -+ hook->prev = lasthook; -+ hook->focus_wnd = hWnd; -+ hook->present = This; -+ return D3D_OK; -+} -+ -+static HRESULT dri3_present_unregister_window_hook( struct DRI3Present *This ) { -+ struct d3d_wnd_hooks *hook = &d3d_hooks; -+ -+ HWND hWnd = This->focus_wnd; -+ -+ /* find hook and remove it */ -+ while (hook->next) { -+ hook = hook->next; -+ if(hook->focus_wnd == hWnd && hook->present == This) { -+ /* remove hook */ -+ hook->prev->next = hook->next; -+ HeapFree(GetProcessHeap(), 0, hook); -+ /* start again at list head */ -+ hook = &d3d_hooks; -+ } -+ } -+ /* remove single process WindowsHook */ -+ if (get_last_hook() == &d3d_hooks && hhook) { -+ if (!UnhookWindowsHookEx(hhook)) { -+ ERR("UnhookWindowsHookEx failed with 0x%08x\n", GetLastError()); -+ } -+ hhook = NULL; -+ } -+ -+ return D3D_OK; -+} -+ -+static BOOL WINAPI -+DRI3Present_GetWindowOccluded( struct DRI3Present *This ) -+{ -+ /* we missed to poll occluded */ -+ if (This->device_needs_reset) { -+ This->device_needs_reset = FALSE; -+ return TRUE; -+ } -+ -+ return This->occluded; -+} -+#endif -+/*----------*/ -+ -+ -+static ID3DPresentVtbl DRI3Present_vtable = { -+ (void *)DRI3Present_QueryInterface, -+ (void *)DRI3Present_AddRef, -+ (void *)DRI3Present_Release, -+ (void *)DRI3Present_SetPresentParameters, -+ (void *)DRI3Present_D3DWindowBufferFromDmaBuf, -+ (void *)DRI3Present_DestroyD3DWindowBuffer, -+ (void *)DRI3Present_WaitBufferReleased, -+ (void *)DRI3Present_FrontBufferCopy, -+ (void *)DRI3Present_PresentBuffer, -+ (void *)DRI3Present_GetRasterStatus, -+ (void *)DRI3Present_GetDisplayMode, -+ (void *)DRI3Present_GetPresentStats, -+ (void *)DRI3Present_GetCursorPos, -+ (void *)DRI3Present_SetCursorPos, -+ (void *)DRI3Present_SetCursor, -+ (void *)DRI3Present_SetGammaRamp, -+ (void *)DRI3Present_GetWindowInfo, -+#ifdef ID3DPresent_GetWindowOccluded -+ (void *)DRI3Present_GetWindowOccluded -+#endif -+}; -+ -+static HRESULT -+DRI3Present_ChangePresentParameters( struct DRI3Present *This, -+ D3DPRESENT_PARAMETERS *params ) -+{ -+ HWND draw_window = params->hDeviceWindow; -+ RECT rect; -+ DEVMODEW new_mode; -+ -+ if (!GetClientRect(draw_window, &rect)) { -+ WARN("GetClientRect failed.\n"); -+ rect.right = 640; -+ rect.bottom = 480; -+ } -+ -+ if (params->BackBufferWidth == 0) { -+ params->BackBufferWidth = rect.right - rect.left; -+ } -+ if (params->BackBufferHeight == 0) { -+ params->BackBufferHeight = rect.bottom - rect.top; -+ } -+ -+ if ((This->params.BackBufferWidth != params->BackBufferWidth) || -+ (This->params.BackBufferHeight != params->BackBufferHeight)) { -+ This->mode_changed = TRUE; -+ } -+ -+ if (This->mode_changed || (This->params.Windowed != params->Windowed)) { -+ if (!params->Windowed) { -+ /* switch display mode */ -+ ZeroMemory(&new_mode, sizeof(DEVMODEW)); -+ new_mode.dmPelsWidth = params->BackBufferWidth; -+ new_mode.dmPelsHeight = params->BackBufferHeight; -+ new_mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; -+ if (params->FullScreen_RefreshRateInHz) { -+ new_mode.dmFields |= DM_DISPLAYFREQUENCY; -+ new_mode.dmDisplayFrequency = params->FullScreen_RefreshRateInHz; -+ } -+ new_mode.dmSize = sizeof(DEVMODEW); -+ DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &new_mode); -+ } else { -+ DRI3Present_ChangeDisplaySettingsIfNeccessary(This, &This->initial_mode); -+ } -+ This->mode_changed = FALSE; -+ -+ if (This->params.Windowed) { -+ if (!params->Windowed) { -+ LONG style, style_ex; -+ boolean drop_wnd_messages; -+ -+ /* switch from window to fullscreen */ -+#ifdef ID3DPresent_GetWindowOccluded -+ if (dri3_present_register_window_hook(This)) { -+ SetWindowPos(This->focus_wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); -+ } -+#else -+ SetWindowPos(This->focus_wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); -+#endif -+ This->style = GetWindowLongW(draw_window, GWL_STYLE); -+ This->style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE); -+ -+ style = fullscreen_style(This->style); -+ style_ex = fullscreen_exstyle(This->style_ex); -+ -+ drop_wnd_messages = This->drop_wnd_messages; -+ This->drop_wnd_messages = TRUE; -+ -+ SetWindowLongW(draw_window, GWL_STYLE, style); -+ SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex); -+ SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth, -+ params->BackBufferHeight, -+ SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); -+ This->drop_wnd_messages = drop_wnd_messages; -+ } -+ } else { -+ if (!params->Windowed) { -+ /* switch from fullscreen to fullscreen */ -+ MoveWindow(draw_window, 0, 0, -+ params->BackBufferWidth, -+ params->BackBufferHeight, -+ TRUE); -+ } else { -+ LONG style, style_ex; -+ boolean drop_wnd_messages; -+ -+ /* switch from fullscreen to window */ -+ style = GetWindowLongW(draw_window, GWL_STYLE); -+ style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE); -+ -+ /* These flags are set by wined3d_device_setup_fullscreen_window, not the -+ * application, and we want to ignore them in the test below, since it's -+ * not the application's fault that they changed. Additionally, we want to -+ * preserve the current status of these flags (i.e. don't restore them) to -+ * more closely emulate the behavior of Direct3D, which leaves these flags -+ * alone when returning to windowed mode. */ -+ This->style ^= (This->style ^ style) & WS_VISIBLE; -+ This->style_ex ^= (This->style_ex ^ style_ex) & WS_EX_TOPMOST; -+ -+ /* Only restore the style if the application didn't modify it during the -+ * fullscreen phase. Some applications change it before calling Reset() -+ * when switching between windowed and fullscreen modes (HL2), some -+ * depend on the original style (Eve Online). */ -+ drop_wnd_messages = This->drop_wnd_messages; -+ This->drop_wnd_messages = TRUE; -+ if (style == fullscreen_style(This->style) && style_ex == fullscreen_exstyle(This->style_ex)) -+ { -+ SetWindowLongW(draw_window, GWL_STYLE, style); -+ SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex); -+ } -+ SetWindowPos(draw_window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | -+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | -+ SWP_NOACTIVATE); -+ This->drop_wnd_messages = drop_wnd_messages; -+ -+#ifdef ID3DPresent_GetWindowOccluded -+ dri3_present_unregister_window_hook(This); -+#endif -+ This->style = 0; -+ This->style_ex = 0; -+ } -+ } -+ } else if (!params->Windowed) { -+ LONG style, style_ex; -+ /* move draw window back to place */ -+ -+ style = GetWindowLongW(draw_window, GWL_STYLE); -+ style_ex = GetWindowLongW(draw_window, GWL_EXSTYLE); -+ -+ style = fullscreen_style(style); -+ style_ex = fullscreen_exstyle(style_ex); -+ -+ SetWindowLongW(draw_window, GWL_STYLE, style); -+ SetWindowLongW(draw_window, GWL_EXSTYLE, style_ex); -+ SetWindowPos(draw_window, HWND_TOPMOST, 0, 0, params->BackBufferWidth, -+ params->BackBufferHeight, -+ SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); -+ } -+ -+ This->params = *params; -+ return D3D_OK; -+} -+ -+static HRESULT -+DRI3Present_new( Display *gdi_display, -+ const WCHAR *devname, -+ D3DPRESENT_PARAMETERS *params, -+ HWND focus_wnd, -+ struct DRI3Present **out, -+ boolean ex, -+ boolean no_window_changes ) -+{ -+ struct DRI3Present *This; -+ -+ if (!focus_wnd) { focus_wnd = params->hDeviceWindow; } -+ if (!focus_wnd) { -+ ERR("No focus HWND specified for presentation backend.\n"); -+ return D3DERR_INVALIDCALL; -+ } -+ -+ This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ sizeof(struct DRI3Present)); -+ if (!This) { -+ ERR("Out of memory.\n"); -+ return E_OUTOFMEMORY; -+ } -+ -+ This->gdi_display = gdi_display; -+ This->vtable = &DRI3Present_vtable; -+ This->refs = 1; -+ This->focus_wnd = focus_wnd; -+ This->params.Windowed = TRUE; -+ This->ex = ex; -+ This->no_window_changes = no_window_changes; -+ -+ strcpyW(This->devname, devname); -+ -+ ZeroMemory(&(This->initial_mode), sizeof(This->initial_mode)); -+ This->initial_mode.dmSize = sizeof(This->initial_mode); -+ -+ EnumDisplaySettingsExW(This->devname, ENUM_CURRENT_SETTINGS, &(This->initial_mode), 0); -+ -+ PRESENTInit(gdi_display, &(This->present_priv)); -+#ifdef D3DADAPTER9_DRI2 -+ if (is_dri2_fallback) -+ DRI2FallbackInit(gdi_display, &(This->dri2_priv)); -+#endif -+ *out = This; -+ -+ return D3D_OK; -+} -+ -+struct DRI3PresentGroup -+{ -+ /* COM vtable */ -+ void *vtable; -+ /* IUnknown reference count */ -+ LONG refs; -+ -+ struct DRI3Present **present_backends; -+ unsigned npresent_backends; -+ Display *gdi_display; -+ boolean ex; -+ boolean no_window_changes; -+}; -+ -+static ULONG WINAPI -+DRI3PresentGroup_AddRef( struct DRI3PresentGroup *This ) -+{ -+ ULONG refs = InterlockedIncrement(&This->refs); -+ TRACE("%p increasing refcount to %u.\n", This, refs); -+ return refs; -+} -+ -+static ULONG WINAPI -+DRI3PresentGroup_Release( struct DRI3PresentGroup *This ) -+{ -+ ULONG refs = InterlockedDecrement(&This->refs); -+ TRACE("%p decreasing refcount to %u.\n", This, refs); -+ if (refs == 0) { -+ unsigned i; -+ if (This->present_backends) { -+ for (i = 0; i < This->npresent_backends; ++i) { -+ if (This->present_backends[i]) -+ DRI3Present_Release(This->present_backends[i]); -+ } -+ HeapFree(GetProcessHeap(), 0, This->present_backends); -+ } -+ HeapFree(GetProcessHeap(), 0, This); -+ } -+ return refs; -+} -+ -+static HRESULT WINAPI -+DRI3PresentGroup_QueryInterface( struct DRI3PresentGroup *This, -+ REFIID riid, -+ void **ppvObject ) -+{ -+ if (!ppvObject) { return E_POINTER; } -+ if (IsEqualGUID(&IID_ID3DPresentGroup, riid) || -+ IsEqualGUID(&IID_IUnknown, riid)) { -+ *ppvObject = This; -+ DRI3PresentGroup_AddRef(This); -+ return S_OK; -+ } -+ -+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); -+ *ppvObject = NULL; -+ -+ return E_NOINTERFACE; -+} -+ -+static UINT WINAPI -+DRI3PresentGroup_GetMultiheadCount( struct DRI3PresentGroup *This ) -+{ -+ FIXME("(%p), stub!\n", This); -+ return 1; -+} -+ -+static HRESULT WINAPI -+DRI3PresentGroup_GetPresent( struct DRI3PresentGroup *This, -+ UINT Index, -+ ID3DPresent **ppPresent ) -+{ -+ if (Index >= DRI3PresentGroup_GetMultiheadCount(This)) { -+ ERR("Index >= MultiHeadCount\n"); -+ return D3DERR_INVALIDCALL; -+ } -+ DRI3Present_AddRef(This->present_backends[Index]); -+ *ppPresent = (ID3DPresent *)This->present_backends[Index]; -+ -+ return D3D_OK; -+} -+ -+static HRESULT WINAPI -+DRI3PresentGroup_CreateAdditionalPresent( struct DRI3PresentGroup *This, -+ D3DPRESENT_PARAMETERS *pPresentationParameters, -+ ID3DPresent **ppPresent ) -+{ -+ HRESULT hr; -+ hr = DRI3Present_new(This->gdi_display, This->present_backends[0]->devname, -+ pPresentationParameters, 0, (struct DRI3Present **)ppPresent, -+ This->ex, This->no_window_changes); -+ return hr; -+} -+ -+static void WINAPI -+DRI3PresentGroup_GetVersion( struct DRI3PresentGroup *This, -+ int *major, -+ int *minor) -+{ -+ *major = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MAJOR; -+ *minor = WINE_D3DADAPTER_DRIVER_PRESENT_VERSION_MINOR; -+} -+ -+static ID3DPresentGroupVtbl DRI3PresentGroup_vtable = { -+ (void *)DRI3PresentGroup_QueryInterface, -+ (void *)DRI3PresentGroup_AddRef, -+ (void *)DRI3PresentGroup_Release, -+ (void *)DRI3PresentGroup_GetMultiheadCount, -+ (void *)DRI3PresentGroup_GetPresent, -+ (void *)DRI3PresentGroup_CreateAdditionalPresent, -+ (void *)DRI3PresentGroup_GetVersion -+}; -+ -+HRESULT -+present_create_present_group( Display *gdi_display, -+ const WCHAR *device_name, -+ UINT adapter, -+ HWND focus_wnd, -+ D3DPRESENT_PARAMETERS *params, -+ unsigned nparams, -+ ID3DPresentGroup **group, -+ boolean ex, -+ boolean no_window_changes ) -+{ -+ struct DRI3PresentGroup *This = -+ HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ sizeof(struct DRI3PresentGroup)); -+ DISPLAY_DEVICEW dd; -+ HRESULT hr; -+ unsigned i; -+ -+ if (!This) { -+ ERR("Out of memory.\n"); -+ return E_OUTOFMEMORY; -+ } -+ -+ This->gdi_display = gdi_display; -+ This->vtable = &DRI3PresentGroup_vtable; -+ This->refs = 1; -+ This->ex = ex; -+ This->no_window_changes = no_window_changes; -+ This->npresent_backends = nparams; -+ This->present_backends = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, -+ This->npresent_backends * -+ sizeof(struct DRI3Present *)); -+ if (!This->present_backends) { -+ DRI3PresentGroup_Release(This); -+ ERR("Out of memory.\n"); -+ return E_OUTOFMEMORY; -+ } -+ -+ if (nparams != 1) { adapter = 0; } -+ for (i = 0; i < This->npresent_backends; ++i) { -+ ZeroMemory(&dd, sizeof(dd)); -+ dd.cb = sizeof(dd); -+ /* find final device name */ -+ if (!EnumDisplayDevicesW(device_name, adapter+i, &dd, 0)) { -+ WARN("Couldn't find subdevice %d from `%s'\n", -+ i, debugstr_w(device_name)); -+ } -+ -+ /* create an ID3DPresent for it */ -+ hr = DRI3Present_new(gdi_display, dd.DeviceName, ¶ms[i], -+ focus_wnd, &This->present_backends[i], -+ This->ex, This->no_window_changes); -+ if (FAILED(hr)) { -+ DRI3PresentGroup_Release(This); -+ return hr; -+ } -+ } -+ -+ *group = (ID3DPresentGroup *)This; -+ TRACE("Returning %p\n", *group); -+ -+ return D3D_OK; -+} -+ -+HRESULT -+present_create_adapter9( Display *gdi_display, -+ HDC hdc, -+ ID3DAdapter9 **out ) -+{ -+ struct x11drv_escape_get_drawable extesc = { X11DRV_GET_DRAWABLE }; -+ HRESULT hr; -+ int fd; -+ -+ if (!d3d9_drm) { -+ ERR("DRM drivers are not supported on your system.\n"); -+ return D3DERR_DRIVERINTERNALERROR; -+ } -+ -+ if (ExtEscape(hdc, X11DRV_ESCAPE, sizeof(extesc), (LPCSTR)&extesc, -+ sizeof(extesc), (LPSTR)&extesc) <= 0) { -+ ERR("X11 drawable lookup failed (hdc=%p)\n", hdc); -+ } -+ -+#ifdef D3DADAPTER9_DRI2 -+ if (!is_dri2_fallback && !DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd)) { -+#else -+ if (!DRI3Open(gdi_display, DefaultScreen(gdi_display), &fd)) { -+#endif -+ ERR("DRI3Open failed (fd=%d)\n", fd); -+ return D3DERR_DRIVERINTERNALERROR; -+ } -+#ifdef D3DADAPTER9_DRI2 -+ if (is_dri2_fallback && !DRI2FallbackOpen(gdi_display, DefaultScreen(gdi_display), &fd)) { -+ ERR("DRI2Open failed (fd=%d)\n", fd); -+ return D3DERR_DRIVERINTERNALERROR; -+ } -+#endif -+ hr = d3d9_drm->create_adapter(fd, out); -+ if (FAILED(hr)) { -+ ERR("Unable to create ID3DAdapter9 (fd=%d)\n", fd); -+ return hr; -+ } -+ -+ TRACE("Created ID3DAdapter9 with fd %d\n", fd); -+ -+ return D3D_OK; -+} -+ -+BOOL -+has_d3dadapter( Display *gdi_display ) -+{ -+ static const void * WINAPI (*pD3DAdapter9GetProc)(const char *); -+ static void *handle = NULL; -+ static int done = 0; -+ -+ char errbuf[256]; -+ -+#if !defined(SONAME_D3DADAPTER9) -+ return FALSE; -+#endif -+ -+ /* like in opengl.c (single threaded assumption OK?) */ -+ if (done) { return handle != NULL; } -+ done = 1; -+ -+ handle = wine_dlopen(D3D_MODULE_DIR "/" SONAME_D3DADAPTER9, -+ RTLD_GLOBAL | RTLD_NOW, errbuf, sizeof(errbuf)); -+ if (!handle) { -+ ERR("Failed to load %s: %s\n", SONAME_D3DADAPTER9, errbuf); -+ goto cleanup; -+ } -+ -+ /* find our entry point in d3dadapter9 */ -+ pD3DAdapter9GetProc = wine_dlsym(handle, "D3DAdapter9GetProc", -+ errbuf, sizeof(errbuf)); -+ if (!pD3DAdapter9GetProc) { -+ ERR("Failed to get the entry point from %s: %s", -+ SONAME_D3DADAPTER9, errbuf); -+ goto cleanup; -+ } -+ -+ /* get a handle to the drm backend struct */ -+ d3d9_drm = pD3DAdapter9GetProc(D3DADAPTER9DRM_NAME); -+ if (!d3d9_drm) { -+ ERR("%s doesn't support the `%s' backend.\n", -+ SONAME_D3DADAPTER9, D3DADAPTER9DRM_NAME); -+ goto cleanup; -+ } -+ -+ /* verify that we're binary compatible */ -+ if (d3d9_drm->major_version != D3DADAPTER9DRM_MAJOR) { -+ ERR("Version mismatch. %s has %d.%d, was expecting %d.x\n", -+ SONAME_D3DADAPTER9, d3d9_drm->major_version, -+ d3d9_drm->minor_version, D3DADAPTER9DRM_MAJOR); -+ goto cleanup; -+ } -+ -+ /* this will be used to store d3d_drawables */ -+ d3d_hwnd_context = XUniqueContext(); -+ -+ if (!PRESENTCheckExtension(gdi_display, 1, 0)) { -+ ERR("Unable to query PRESENT.\n"); -+ goto cleanup; -+ } -+ -+ if (!DRI3CheckExtension(gdi_display, 1, 0)) { -+#ifndef D3DADAPTER9_DRI2 -+ ERR("Unable to query DRI3.\n"); -+ goto cleanup; -+#else -+ ERR("Unable to query DRI3. Trying DRI2 fallback (slower performance).\n"); -+ is_dri2_fallback = 1; -+ if (!DRI2FallbackCheckSupport(gdi_display)) { -+ ERR("DRI2 fallback unsupported\n"); -+ goto cleanup; -+ } -+#endif -+ } -+ -+ return TRUE; -+ -+cleanup: -+ ERR("\033[1;31m\nNative Direct3D 9 will be unavailable." -+ "\nFor more information visit https://wiki.ixit.cz/d3d9\033[0m\n"); -+ if (handle) { -+ wine_dlclose(handle, NULL, 0); -+ handle = NULL; -+ } -+ -+ return FALSE; -+} -diff --git a/dlls/d3d9-nine/present.h b/dlls/d3d9-nine/present.h -new file mode 100644 -index 0000000..52791a5 ---- /dev/null -+++ b/dlls/d3d9-nine/present.h -@@ -0,0 +1,36 @@ -+/* -+ * Wine present interface -+ * -+ * Copyright 2015 Patrick Rudolph -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#ifndef __WINE_PRESENT_H -+#define __WINE_PRESENT_H -+ -+#ifndef __WINE_CONFIG_H -+# error You must include config.h to use this header -+#endif -+ -+#include <X11/Xlib.h> -+ -+HRESULT present_create_present_group(Display *gdi_display, const WCHAR *device_name, UINT adapter, HWND focus, D3DPRESENT_PARAMETERS *params, unsigned nparams, ID3DPresentGroup **group, boolean ex, boolean no_window_changes); -+ -+HRESULT present_create_adapter9(Display *gdi_display, HDC hdc, ID3DAdapter9 **adapter); -+ -+BOOL has_d3dadapter(Display *gdi_display); -+ -+#endif /* __WINE_DRI3_H */ -diff --git a/dlls/d3d9-nine/version.rc b/dlls/d3d9-nine/version.rc -new file mode 100644 -index 0000000..bfafc2f ---- /dev/null -+++ b/dlls/d3d9-nine/version.rc -@@ -0,0 +1,26 @@ -+/* -+ * Copyright 2015 Patrick Rudolph -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#define WINE_FILEDESCRIPTION_STR "Wine Gallium Nine Direct3D" -+#define WINE_FILENAME_STR "d3d9-nine.dll" -+#define WINE_FILEVERSION 5,3,1,904 -+#define WINE_FILEVERSION_STR "5.3.1.904" -+#define WINE_PRODUCTVERSION 5,3,1,904 -+#define WINE_PRODUCTVERSION_STR "5.3.1.904" -+ -+#include "wine/wine_common_ver.rc" -diff --git a/dlls/d3d9/Makefile.in b/dlls/d3d9/Makefile.in -index 1c05f5a..dc06d68 100644 ---- a/dlls/d3d9/Makefile.in -+++ b/dlls/d3d9/Makefile.in -@@ -1,6 +1,6 @@ - MODULE = d3d9.dll - IMPORTLIB = d3d9 --IMPORTS = dxguid uuid wined3d -+IMPORTS = dxguid uuid advapi32 wined3d - - C_SRCS = \ - buffer.c \ -diff --git a/dlls/d3d9/tests/d3d9ex.c b/dlls/d3d9/tests/d3d9ex.c -index 151db41..5314915 100644 ---- a/dlls/d3d9/tests/d3d9ex.c -+++ b/dlls/d3d9/tests/d3d9ex.c -@@ -1410,6 +1410,7 @@ static void test_lost_device(void) - HRESULT hr; - BOOL ret; - struct device_desc desc; -+ IDirect3DSwapChain9 *swapchain; - - window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW, - 0, 0, 640, 480, NULL, NULL, NULL, NULL); -@@ -1434,6 +1435,12 @@ static void test_lost_device(void) - hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL); - ok(hr == S_PRESENT_OCCLUDED, "Got unexpected hr %#x.\n", hr); - -+ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain); -+ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr); -+ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0); -+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); -+ IDirect3DSwapChain9_Release(swapchain); -+ - ret = SetForegroundWindow(GetDesktopWindow()); - ok(ret, "Failed to set foreground window.\n"); - hr = IDirect3DDevice9Ex_TestCooperativeLevel(device); -@@ -1447,6 +1454,12 @@ static void test_lost_device(void) - hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL); - ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); - -+ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain); -+ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr); -+ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0); -+ ok(hr == S_PRESENT_OCCLUDED, "Got unexpected hr %#x.\n", hr); -+ IDirect3DSwapChain9_Release(swapchain); -+ - ret = SetForegroundWindow(window); - ok(ret, "Failed to set foreground window.\n"); - hr = IDirect3DDevice9Ex_TestCooperativeLevel(device); -@@ -1460,6 +1473,12 @@ static void test_lost_device(void) - hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL); - ok(hr == S_PRESENT_OCCLUDED, "Got unexpected hr %#x.\n", hr); - -+ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain); -+ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr); -+ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0); -+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); -+ IDirect3DSwapChain9_Release(swapchain); -+ - desc.width = 1024; - desc.height = 768; - hr = reset_device(device, &desc); -@@ -1489,6 +1508,12 @@ static void test_lost_device(void) - hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL); - todo_wine ok(hr == S_PRESENT_MODE_CHANGED, "Got unexpected hr %#x.\n", hr); - -+ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain); -+ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr); -+ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0); -+ ok(hr == S_PRESENT_MODE_CHANGED, "Got unexpected hr %#x.\n", hr); -+ IDirect3DSwapChain9_Release(swapchain); -+ - hr = reset_device(device, &desc); - ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); - hr = IDirect3DDevice9Ex_TestCooperativeLevel(device); -@@ -1502,6 +1527,12 @@ static void test_lost_device(void) - hr = IDirect3DDevice9Ex_CheckDeviceState(device, NULL); - ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); - -+ hr = IDirect3DDevice9Ex_GetSwapChain(device, 0, &swapchain); -+ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr); -+ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0); -+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); -+ IDirect3DSwapChain9_Release(swapchain); -+ - ret = SetForegroundWindow(GetDesktopWindow()); - ok(ret, "Failed to set foreground window.\n"); - hr = IDirect3DDevice9Ex_TestCooperativeLevel(device); -diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c -index 326e789..0ff7211 100644 ---- a/dlls/d3d9/tests/device.c -+++ b/dlls/d3d9/tests/device.c -@@ -8222,10 +8222,10 @@ done: - - static void test_vidmem_accounting(void) - { -- IDirect3DDevice9 *device; -+ IDirect3DDevice9 *device, *device2; - IDirect3D9 *d3d9; - ULONG refcount; -- HWND window; -+ HWND window, window2; - HRESULT hr = D3D_OK; - IDirect3DTexture9 *textures[20]; - unsigned int i; -@@ -8233,6 +8233,8 @@ static void test_vidmem_accounting(void) - - window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW, - 0, 0, 640, 480, 0, 0, 0, 0); -+ window2 = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW, -+ 0, 0, 640, 480, 0, 0, 0, 0); - d3d9 = Direct3DCreate9(D3D_SDK_VERSION); - ok(!!d3d9, "Failed to create a D3D object.\n"); - if (!(device = create_device(d3d9, window, NULL))) -@@ -8267,6 +8269,43 @@ static void test_vidmem_accounting(void) - IDirect3DTexture9_Release(textures[i]); - } - -+ /* Multi-device testing */ -+ if (!(device2 = create_device(d3d9, window2, NULL))) -+ { -+ skip("Failed to create a D3D device, skipping tests.\n"); -+ refcount = IDirect3DDevice9_Release(device); -+ ok(!refcount, "Device has %u references left.\n", refcount); -+ IDirect3D9_Release(d3d9); -+ DestroyWindow(window2); -+ DestroyWindow(window); -+ return; -+ } -+ -+ vidmem_start = IDirect3DDevice9_GetAvailableTextureMem(device); -+ memset(textures, 0, sizeof(textures)); -+ for (i = 0; (i < sizeof(textures) / sizeof(*textures)) && SUCCEEDED(hr); i++) -+ { -+ hr = IDirect3DDevice9_CreateTexture(device2, 1024, 1024, 1, D3DUSAGE_RENDERTARGET, -+ D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &textures[i], NULL); -+ /* D3DERR_OUTOFVIDEOMEMORY is returned when the card runs out of video memory -+ * E_FAIL is returned on address space or system memory exhaustion */ -+ ok(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY, -+ "Failed to create texture, hr %#x.\n", hr); -+ } -+ vidmem_end = IDirect3DDevice9_GetAvailableTextureMem(device); -+ -+ /* Windows 7 uses device private counters */ -+ ok(vidmem_start > vidmem_end || broken(vidmem_start == vidmem_end), "Expected available texture memory to decrease during texture creation.\n"); -+ diff = vidmem_start - vidmem_end; -+ ok(diff > 1024 * 1024 * 2 * i || broken(diff == 0), "Expected a video memory difference of at least %u MB, got %u MB.\n", -+ 2 * i, diff / 1024 / 1024); -+ -+ for (i = 0; i < sizeof(textures) / sizeof(*textures); i++) -+ { -+ if (textures[i]) -+ IDirect3DTexture9_Release(textures[i]); -+ } -+ - refcount = IDirect3DDevice9_Release(device); - ok(!refcount, "Device has %u references left.\n", refcount); - IDirect3D9_Release(d3d9); -@@ -9987,6 +10026,7 @@ static void test_lost_device(void) - HWND window; - HRESULT hr; - BOOL ret; -+ IDirect3DSwapChain9 *swapchain; - - window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW, - 0, 0, 640, 480, NULL, NULL, NULL, NULL); -@@ -10014,6 +10054,12 @@ static void test_lost_device(void) - hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); - ok(hr == D3DERR_DEVICELOST, "Got unexpected hr %#x.\n", hr); - -+ hr = IDirect3DDevice9_GetSwapChain(device, 0, &swapchain); -+ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr); -+ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0); -+ ok(hr == D3DERR_DEVICELOST, "Got unexpected hr %#x.\n", hr); -+ IDirect3DSwapChain9_Release(swapchain); -+ - ret = ShowWindow(window, SW_RESTORE); - ok(ret, "Failed to restore window.\n"); - ret = SetForegroundWindow(window); -@@ -10023,6 +10069,12 @@ static void test_lost_device(void) - hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); - ok(hr == D3DERR_DEVICELOST, "Got unexpected hr %#x.\n", hr); - -+ hr = IDirect3DDevice9_GetSwapChain(device, 0, &swapchain); -+ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr); -+ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0); -+ ok(hr == D3DERR_DEVICELOST, "Got unexpected hr %#x.\n", hr); -+ IDirect3DSwapChain9_Release(swapchain); -+ - hr = reset_device(device, &device_desc); - ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); - hr = IDirect3DDevice9_TestCooperativeLevel(device); -@@ -10030,6 +10082,12 @@ static void test_lost_device(void) - hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); - ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); - -+ hr = IDirect3DDevice9_GetSwapChain(device, 0, &swapchain); -+ ok(SUCCEEDED(hr), "Failed to get swapchain, hr %#x.\n", hr); -+ hr = IDirect3DSwapChain9_Present(swapchain, NULL, NULL, NULL, NULL, 0); -+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); -+ IDirect3DSwapChain9_Release(swapchain); -+ - device_desc.flags = 0; - hr = reset_device(device, &device_desc); - ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); -diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c -index b328b94..74d9dd9 100644 ---- a/dlls/d3d9/tests/visual.c -+++ b/dlls/d3d9/tests/visual.c -@@ -8535,6 +8535,167 @@ done: - DestroyWindow(window); - } - -+static void test_blend_invalid_arg(void) -+{ -+ IDirect3DSurface9 *backbuffer, *offscreen; -+ IDirect3DTexture9 *offscreenTexture; -+ IDirect3DDevice9 *device; -+ IDirect3D9 *d3d; -+ D3DCOLOR color; -+ ULONG refcount; -+ HWND window; -+ HRESULT hr; -+ DWORD rs; -+ -+ static const struct -+ { -+ struct vec3 position; -+ DWORD diffuse; -+ } -+ quad1[] = -+ { -+ {{-1.0f, -1.0f, 0.1f}, 0x4000ff00}, -+ {{-1.0f, 0.0f, 0.1f}, 0x4000ff00}, -+ {{ 0.0f, -1.0f, 0.1f}, 0x4000ff00}, -+ {{ 0.0f, 0.0f, 0.1f}, 0x4000ff00}, -+ }, -+ quad2[] = -+ { -+ {{ 0.0f, 0.0f, 0.1f}, 0x4000ff00}, -+ {{ 0.0f, 1.0f, 0.1f}, 0x4000ff00}, -+ {{ 1.0f, 0.0f, 0.1f}, 0x4000ff00}, -+ {{ 1.0f, 1.0f, 0.1f}, 0x4000ff00}, -+ }, -+ quad3[] = -+ { -+ {{-1.0f, 0.0f, 0.1f}, 0xc00000ff}, -+ {{-1.0f, 1.0f, 0.1f}, 0xc00000ff}, -+ {{ 0.0f, 0.0f, 0.1f}, 0xc00000ff}, -+ {{ 0.0f, 1.0f, 0.1f}, 0xc00000ff}, -+ }, -+ quad4[] = -+ { -+ {{ 0.0f, -1.0f, 0.1f}, 0xc00000ff}, -+ {{ 0.0f, 0.0f, 0.1f}, 0xc00000ff}, -+ {{ 1.0f, -1.0f, 0.1f}, 0xc00000ff}, -+ {{ 1.0f, 0.0f, 0.1f}, 0xc00000ff}, -+ }; -+ -+ window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, -+ 0, 0, 640, 480, NULL, NULL, NULL, NULL); -+ d3d = Direct3DCreate9(D3D_SDK_VERSION); -+ ok(!!d3d, "Failed to create a D3D object.\n"); -+ if (!(device = create_device(d3d, window, window, TRUE))) -+ { -+ skip("Failed to create a D3D device, skipping tests.\n"); -+ goto done; -+ } -+ /* Clear the render target with alpha = 0.5 */ -+ hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x80ff0000, 1.0f, 0); -+ ok(hr == D3D_OK, "Clear failed, hr = %08x\n", hr); -+ -+ hr = IDirect3DDevice9_CreateTexture(device, 128, 128, 1, D3DUSAGE_RENDERTARGET, -+ D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &offscreenTexture, NULL); -+ ok(SUCCEEDED(hr), "Failed to create texture, hr %#x.\n", hr); -+ -+ hr = IDirect3DDevice9_GetBackBuffer(device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); -+ ok(hr == D3D_OK, "Can't get back buffer, hr = %08x\n", hr); -+ -+ hr = IDirect3DTexture9_GetSurfaceLevel(offscreenTexture, 0, &offscreen); -+ ok(hr == D3D_OK, "Can't get offscreen surface, hr = %08x\n", hr); -+ -+ hr = IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE); -+ ok(hr == D3D_OK, "IDirect3DDevice9_SetFVF failed, hr = %#08x\n", hr); -+ -+ hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); -+ ok(hr == D3D_OK, "SetTextureStageState failed, hr = %08x\n", hr); -+ hr = IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE); -+ ok(hr == D3D_OK, "SetTextureStageState failed, hr = %08x\n", hr); -+ hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MINFILTER, D3DTEXF_POINT); -+ ok(SUCCEEDED(hr), "SetSamplerState D3DSAMP_MINFILTER failed (0x%08x)\n", hr); -+ hr = IDirect3DDevice9_SetSamplerState(device, 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); -+ ok(SUCCEEDED(hr), "SetSamplerState D3DSAMP_MAGFILTER failed (0x%08x)\n", hr); -+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE); -+ ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState returned %08x\n", hr); -+ -+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_ALPHABLENDENABLE, TRUE); -+ ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderState failed, hr = %08x\n", hr); -+ hr = IDirect3DDevice9_BeginScene(device); -+ ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); -+ -+ /* draw quad to test default renderstate -+ * expect D3DRS_SRCBLEND == D3DBLEND_ONE -+ * expect D3DRS_DESTBLEND == D3DBLEND_ZERO */ -+ hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad1, sizeof(quad1[0])); -+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr); -+ -+ /* set invalid value and expect D3DBLEND_ZERO instead */ -+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_SRCBLEND, 0); -+ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); -+ hr = IDirect3DDevice9_GetRenderState(device, D3DRS_SRCBLEND, &rs); -+ ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr); -+ ok(rs == 0, "Unexpected renderstate %#x.\n", rs); -+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); -+ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); -+ -+ hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad2, sizeof(quad2[0])); -+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr); -+ /* set non default valid values */ -+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); -+ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); -+ hr = IDirect3DDevice9_GetRenderState(device, D3DRS_SRCBLEND, &rs); -+ ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr); -+ ok(rs == D3DBLEND_SRCALPHA, "Unexpected renderstate %#x.\n", rs); -+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); -+ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); -+ hr = IDirect3DDevice9_GetRenderState(device, D3DRS_DESTBLEND, &rs); -+ ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr); -+ ok(rs == D3DBLEND_INVSRCALPHA, "Failed to get render state, hr %#x.\n", hr); -+ -+ hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad3, sizeof(quad3[0])); -+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr); -+ -+ /* set invalid value and expect D3DBLEND_ZERO instead */ -+ hr = IDirect3DDevice9_SetRenderState(device, D3DRS_DESTBLEND, 200); -+ ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr); -+ hr = IDirect3DDevice9_GetRenderState(device, D3DRS_DESTBLEND, &rs); -+ ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr); -+ ok(rs == 200, "Failed to get render state, hr %#x.\n", hr); -+ -+ hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, quad4, sizeof(quad4[0])); -+ ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr); -+ -+ hr = IDirect3DDevice9_EndScene(device); -+ ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr); -+ -+ color = getPixelColor(device, 160, 360); -+ ok(color_match(color, D3DCOLOR_ARGB(0x00, 0x00, 0xff, 0x00), 1), -+ "D3DRS_SRCBLEND ONE returned color %08x, expected 0x0000FF00\n", color); -+ -+ color = getPixelColor(device, 480, 120); -+ ok(color_match(color, D3DCOLOR_ARGB(0x00, 0xbf, 0x00, 0x00), 1), -+ "invalid D3DRS_SRCBLEND returned color %08x, expected 0x00bf0000\n", color); -+ -+ color = getPixelColor(device, 160, 120); -+ ok(color_match(color, D3DCOLOR_ARGB(0x00, 0x3f, 0x00, 0xC0), 1), -+ "D3DRS_SRCBLEND SRCALPHA returned color %08x, expected 0x003f00C0\n", color); -+ -+ color = getPixelColor(device, 480, 360); -+ ok(color_match(color, D3DCOLOR_ARGB(0x00, 0x00, 0x00, 0xC0), 1), -+ "invalid D3DRS_DESTBLEND returned color %08x, expected 0x000000C0\n", color); -+ -+ IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); -+ -+ IDirect3DSurface9_Release(backbuffer); -+ IDirect3DTexture9_Release(offscreenTexture); -+ IDirect3DSurface9_Release(offscreen); -+ refcount = IDirect3DDevice9_Release(device); -+ ok(!refcount, "Device has %u references left.\n", refcount); -+done: -+ IDirect3D9_Release(d3d); -+ DestroyWindow(window); -+} -+ - static void fixed_function_decl_test(void) - { - IDirect3DVertexDeclaration9 *dcl_float = NULL, *dcl_short = NULL, *dcl_ubyte = NULL, *dcl_color = NULL; -@@ -12734,6 +12895,9 @@ static void alphatest_test(void) - } - testdata[] = - { -+ /* test invalid values, D3DCMP_NEVER for values less than D3DCMP_NEVER, -+ * D3DCMP_ALWAYS for values greater than D3DCMP_ALWAYS */ -+ {D3DCMP_NEVER-1, ALPHATEST_FAILED, ALPHATEST_FAILED, ALPHATEST_FAILED}, - {D3DCMP_NEVER, ALPHATEST_FAILED, ALPHATEST_FAILED, ALPHATEST_FAILED}, - {D3DCMP_LESS, ALPHATEST_PASSED, ALPHATEST_FAILED, ALPHATEST_FAILED}, - {D3DCMP_EQUAL, ALPHATEST_FAILED, ALPHATEST_PASSED, ALPHATEST_FAILED}, -@@ -12742,6 +12906,10 @@ static void alphatest_test(void) - {D3DCMP_NOTEQUAL, ALPHATEST_PASSED, ALPHATEST_FAILED, ALPHATEST_PASSED}, - {D3DCMP_GREATEREQUAL, ALPHATEST_FAILED, ALPHATEST_PASSED, ALPHATEST_PASSED}, - {D3DCMP_ALWAYS, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED}, -+ {D3DCMP_ALWAYS+1, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED}, -+ {D3DCMP_ALWAYS+2, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED}, -+ {D3DCMP_ALWAYS+3, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED}, -+ {0xdeadbeef, ALPHATEST_PASSED, ALPHATEST_PASSED, ALPHATEST_PASSED}, - }; - static const struct - { -@@ -18087,6 +18255,27 @@ static void test_negative_fixedfunction_fog(void) - D3DFOG_LINEAR, D3DFOG_NONE, 0x0000ff00, 0x0000ff00, 0x0000ff00}, - {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, - D3DFOG_EXP, D3DFOG_NONE, 0x009b6400, 0x009b6400, 0x009b6400}, -+ /* test invalid values, expect a modulo 4 on samplerstate */ -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+1, D3DFOG_NONE, 0x0000ff00, 0x009b6400, 0x009b6400}, -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+2, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400}, -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+3, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400}, -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+4, D3DFOG_NONE, 0x007f7f00, 0x009b6400, 0x009b6400}, -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+5, D3DFOG_NONE, 0x0000ff00, 0x009b6400, 0x009b6400}, -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+6, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400}, -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+7, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400}, -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+8, D3DFOG_NONE, 0x007f7f00, 0x009b6400, 0x009b6400}, -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+9, D3DFOG_NONE, 0x0000ff00, 0x009b6400, 0x009b6400}, -+ {D3DFVF_XYZ, quad, sizeof(*quad), &zero, { 0.0f}, {1.0f}, -+ D3DFOG_LINEAR+10, D3DFOG_NONE, 0x00c73800, 0x009b6400, 0x009b6400}, - }; - D3DCAPS9 caps; - -@@ -20511,4 +20700,5 @@ START_TEST(visual) - test_depthbias(); - test_flip(); - test_uninitialized_varyings(); -+ test_blend_invalid_arg(); - } -diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c -index 74feb97..d331513 100644 ---- a/dlls/ntdll/loader.c -+++ b/dlls/ntdll/loader.c -@@ -92,6 +92,7 @@ struct builtin_load_info - { - const WCHAR *load_path; - const WCHAR *filename; -+ const WCHAR *fakemodule; - NTSTATUS status; - WINE_MODREF *wm; - }; -@@ -117,7 +118,8 @@ static WINE_MODREF *cached_modref; - static WINE_MODREF *current_modref; - static WINE_MODREF *last_failed_modref; - --static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm ); -+static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, LPCWSTR fakemodule, -+ DWORD flags, WINE_MODREF** pwm ); - static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved ); - static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, - DWORD exp_size, DWORD ordinal, LPCWSTR load_path ); -@@ -443,7 +445,7 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS - if (!(wm = find_basename_module( mod_name ))) - { - TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward ); -- if (load_dll( load_path, mod_name, 0, &wm ) == STATUS_SUCCESS && -+ if (load_dll( load_path, mod_name, NULL, 0, &wm ) == STATUS_SUCCESS && - !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) - { - if (process_attach( wm, NULL ) != STATUS_SUCCESS) -@@ -592,7 +594,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d - { - ascii_to_unicode( buffer, name, len ); - buffer[len] = 0; -- status = load_dll( load_path, buffer, 0, &wmImp ); -+ status = load_dll( load_path, buffer, NULL, 0, &wmImp ); - } - else /* need to allocate a larger buffer */ - { -@@ -600,7 +602,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d - if (!ptr) return NULL; - ascii_to_unicode( ptr, name, len ); - ptr[len] = 0; -- status = load_dll( load_path, ptr, 0, &wmImp ); -+ status = load_dll( load_path, ptr, NULL, 0, &wmImp ); - RtlFreeHeap( GetProcessHeap(), 0, ptr ); - } - -@@ -916,7 +918,7 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path ) - * Allocate a WINE_MODREF structure and add it to the process list - * The loader_section must be locked while calling this function. - */ --static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename ) -+static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename, LPCWSTR fakemodule ) - { - WINE_MODREF *wm; - const WCHAR *p; -@@ -939,7 +941,7 @@ static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename ) - wm->ldr.TimeDateStamp = 0; - wm->ldr.ActivationContext = 0; - -- RtlCreateUnicodeString( &wm->ldr.FullDllName, filename ); -+ RtlCreateUnicodeString( &wm->ldr.FullDllName, fakemodule ? fakemodule : filename ); - if ((p = strrchrW( wm->ldr.FullDllName.Buffer, '\\' ))) p++; - else p = wm->ldr.FullDllName.Buffer; - RtlInitUnicodeString( &wm->ldr.BaseDllName, p ); -@@ -1578,7 +1580,7 @@ static void load_builtin_callback( void *module, const char *filename ) - return; - } - -- wm = alloc_module( module, fullname ); -+ wm = alloc_module( module, fullname, builtin_load_info->fakemodule ); - RtlFreeHeap( GetProcessHeap(), 0, fullname ); - if (!wm) - { -@@ -1760,8 +1762,8 @@ static NTSTATUS perform_relocations( void *module, SIZE_T len ) - /****************************************************************************** - * load_native_dll (internal) - */ --static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file, -- DWORD flags, WINE_MODREF** pwm ) -+static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, LPCWSTR fakemodule, -+ HANDLE file, DWORD flags, WINE_MODREF** pwm ) - { - void *module; - HANDLE mapping; -@@ -1795,7 +1797,7 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file, - - /* create the MODREF */ - -- if (!(wm = alloc_module( module, name ))) -+ if (!(wm = alloc_module( module, name, fakemodule ))) - { - status = STATUS_NO_MEMORY; - goto done; -@@ -1859,8 +1861,8 @@ done: - /*********************************************************************** - * load_builtin_dll - */ --static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, HANDLE file, -- DWORD flags, WINE_MODREF** pwm ) -+static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, LPCWSTR fakemodule, -+ HANDLE file, DWORD flags, WINE_MODREF** pwm ) - { - char error[256], dllname[MAX_PATH]; - const WCHAR *name, *p; -@@ -1880,6 +1882,7 @@ static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, HANDLE file, - */ - info.load_path = load_path; - info.filename = NULL; -+ info.fakemodule = fakemodule; - info.status = STATUS_SUCCESS; - info.wm = NULL; - -@@ -2198,14 +2201,14 @@ overflow: - return STATUS_BUFFER_TOO_SMALL; - } - -- - /*********************************************************************** - * load_dll (internal) - * - * Load a PE style module according to the load order. - * The loader_section must be locked while calling this function. - */ --static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm ) -+static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, LPCWSTR fakemodule, -+ DWORD flags, WINE_MODREF** pwm ) - { - enum loadorder loadorder; - WCHAR buffer[64]; -@@ -2242,6 +2245,25 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_ - } - - main_exe = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress ); -+ -+ /* handle dll redirection */ -+ if (!fakemodule) -+ { -+ BYTE buffer2[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH * sizeof(WCHAR)]; -+ WCHAR *redirect = get_redirect( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, -+ filename, buffer2, sizeof(buffer2) ); -+ if (redirect) -+ { -+ FIXME("Loader redirect from %s to %s\n", debugstr_w(libname), debugstr_w(redirect)); -+ -+ nts = load_dll( load_path, redirect, filename, flags, pwm ); -+ -+ if (handle) NtClose( handle ); -+ if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename ); -+ return nts; -+ } -+ } -+ - loadorder = get_load_order( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, filename ); - - if (handle && is_fake_dll( handle )) -@@ -2264,22 +2286,22 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_ - if (!handle) nts = STATUS_DLL_NOT_FOUND; - else - { -- nts = load_native_dll( load_path, filename, handle, flags, pwm ); -+ nts = load_native_dll( load_path, filename, fakemodule, handle, flags, pwm ); - if (nts == STATUS_INVALID_IMAGE_NOT_MZ) - /* not in PE format, maybe it's a builtin */ -- nts = load_builtin_dll( load_path, filename, handle, flags, pwm ); -+ nts = load_builtin_dll( load_path, filename, fakemodule, handle, flags, pwm ); - } - if (nts == STATUS_DLL_NOT_FOUND && loadorder == LO_NATIVE_BUILTIN) -- nts = load_builtin_dll( load_path, filename, 0, flags, pwm ); -+ nts = load_builtin_dll( load_path, filename, fakemodule, 0, flags, pwm ); - break; - case LO_BUILTIN: - case LO_BUILTIN_NATIVE: - case LO_DEFAULT: /* default is builtin,native */ -- nts = load_builtin_dll( load_path, filename, handle, flags, pwm ); -+ nts = load_builtin_dll( load_path, filename, fakemodule, handle, flags, pwm ); - if (!handle) break; /* nothing else we can try */ - /* file is not a builtin library, try without using the specified file */ - if (nts != STATUS_SUCCESS) -- nts = load_builtin_dll( load_path, filename, 0, flags, pwm ); -+ nts = load_builtin_dll( load_path, filename, fakemodule, 0, flags, pwm ); - if (nts == STATUS_SUCCESS && loadorder == LO_DEFAULT && - (MODULE_InitDLL( *pwm, DLL_WINE_PREATTACH, NULL ) != STATUS_SUCCESS)) - { -@@ -2289,7 +2311,7 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_ - nts = STATUS_DLL_NOT_FOUND; - } - if (nts == STATUS_DLL_NOT_FOUND && loadorder != LO_BUILTIN) -- nts = load_native_dll( load_path, filename, handle, flags, pwm ); -+ nts = load_native_dll( load_path, filename, fakemodule, handle, flags, pwm ); - break; - } - -@@ -2322,7 +2344,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags, - RtlEnterCriticalSection( &loader_section ); - - if (!path_name) path_name = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer; -- nts = load_dll( path_name, libname->Buffer, flags, &wm ); -+ nts = load_dll( path_name, libname->Buffer, NULL, flags, &wm ); - - if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) - { -@@ -3285,7 +3307,7 @@ void __wine_process_init(void) - /* setup the load callback and create ntdll modref */ - wine_dll_set_callback( load_builtin_callback ); - -- if ((status = load_builtin_dll( NULL, kernel32W, 0, 0, &wm )) != STATUS_SUCCESS) -+ if ((status = load_builtin_dll( NULL, kernel32W, NULL, 0, 0, &wm )) != STATUS_SUCCESS) - { - MESSAGE( "wine: could not load kernel32.dll, status %x\n", status ); - exit(1); -diff --git a/dlls/ntdll/loadorder.c b/dlls/ntdll/loadorder.c -index 401d256..c7c4592 100644 ---- a/dlls/ntdll/loadorder.c -+++ b/dlls/ntdll/loadorder.c -@@ -290,102 +290,165 @@ static inline enum loadorder get_env_load_order( const WCHAR *module ) - - - /*************************************************************************** -- * get_standard_key -+ * open_user_reg_key -+ * -+ * Return a handle to a registry key under HKCU. -+ */ -+static HANDLE open_user_reg_key(const WCHAR *key_name) -+{ -+ HANDLE hkey, root; -+ OBJECT_ATTRIBUTES attr; -+ UNICODE_STRING nameW; -+ -+ RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); -+ attr.Length = sizeof(attr); -+ attr.RootDirectory = root; -+ attr.ObjectName = &nameW; -+ attr.Attributes = 0; -+ attr.SecurityDescriptor = NULL; -+ attr.SecurityQualityOfService = NULL; -+ RtlInitUnicodeString( &nameW, key_name ); -+ -+ if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) hkey = 0; -+ NtClose( root ); -+ -+ return hkey; -+} -+ -+ -+/*************************************************************************** -+ * open_app_reg_key -+ * -+ * Return a handle to an app-specific registry key. -+ */ -+static HANDLE open_app_reg_key( const WCHAR *sub_key, const WCHAR *app_name ) -+{ -+ static const WCHAR AppDefaultsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', -+ 'A','p','p','D','e','f','a','u','l','t','s','\\',0}; -+ WCHAR *str; -+ HANDLE hkey; -+ -+ str = RtlAllocateHeap( GetProcessHeap(), 0, -+ sizeof(AppDefaultsW) + -+ strlenW(sub_key) * sizeof(WCHAR) + -+ strlenW(app_name) * sizeof(WCHAR) ); -+ if (!str) return 0; -+ strcpyW( str, AppDefaultsW ); -+ strcatW( str, app_name ); -+ strcatW( str, sub_key ); -+ -+ hkey = open_user_reg_key( str ); -+ RtlFreeHeap( GetProcessHeap(), 0, str ); -+ return hkey; -+} -+ -+ -+/*************************************************************************** -+ * get_override_standard_key - * - * Return a handle to the standard DllOverrides registry section. - */ --static HANDLE get_standard_key(void) -+static HANDLE get_override_standard_key(void) - { - static const WCHAR DllOverridesW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', - 'D','l','l','O','v','e','r','r','i','d','e','s',0}; - static HANDLE std_key = (HANDLE)-1; - - if (std_key == (HANDLE)-1) -- { -- OBJECT_ATTRIBUTES attr; -- UNICODE_STRING nameW; -- HANDLE root; -- -- RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); -- attr.Length = sizeof(attr); -- attr.RootDirectory = root; -- attr.ObjectName = &nameW; -- attr.Attributes = 0; -- attr.SecurityDescriptor = NULL; -- attr.SecurityQualityOfService = NULL; -- RtlInitUnicodeString( &nameW, DllOverridesW ); -- -- /* @@ Wine registry key: HKCU\Software\Wine\DllOverrides */ -- if (NtOpenKey( &std_key, KEY_ALL_ACCESS, &attr )) std_key = 0; -- NtClose( root ); -- } -+ std_key = open_user_reg_key( DllOverridesW ); -+ - return std_key; - } - - - /*************************************************************************** -- * get_app_key -+ * get_override_app_key - * - * Get the registry key for the app-specific DllOverrides list. - */ --static HANDLE get_app_key( const WCHAR *app_name ) -+static HANDLE get_override_app_key( const WCHAR *app_name ) - { -- OBJECT_ATTRIBUTES attr; -- UNICODE_STRING nameW; -- HANDLE root; -- WCHAR *str; -- static const WCHAR AppDefaultsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', -- 'A','p','p','D','e','f','a','u','l','t','s','\\',0}; - static const WCHAR DllOverridesW[] = {'\\','D','l','l','O','v','e','r','r','i','d','e','s',0}; - static HANDLE app_key = (HANDLE)-1; - -- if (app_key != (HANDLE)-1) return app_key; -+ if (app_key == (HANDLE)-1) -+ app_key = open_app_reg_key( DllOverridesW, app_name ); - -- str = RtlAllocateHeap( GetProcessHeap(), 0, -- sizeof(AppDefaultsW) + sizeof(DllOverridesW) + -- strlenW(app_name) * sizeof(WCHAR) ); -- if (!str) return 0; -- strcpyW( str, AppDefaultsW ); -- strcatW( str, app_name ); -- strcatW( str, DllOverridesW ); -+ return app_key; -+} - -- RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); -- attr.Length = sizeof(attr); -- attr.RootDirectory = root; -- attr.ObjectName = &nameW; -- attr.Attributes = 0; -- attr.SecurityDescriptor = NULL; -- attr.SecurityQualityOfService = NULL; -- RtlInitUnicodeString( &nameW, str ); - -- /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DllOverrides */ -- if (NtOpenKey( &app_key, KEY_ALL_ACCESS, &attr )) app_key = 0; -- NtClose( root ); -- RtlFreeHeap( GetProcessHeap(), 0, str ); -+/*************************************************************************** -+ * get_redirect_standard_key -+ * -+ * Return a handle to the standard DllRedirects registry section. -+ */ -+static HANDLE get_redirect_standard_key(void) -+{ -+ static const WCHAR DllRedirectsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', -+ 'D','l','l','R','e','d','i','r','e','c','t','s',0}; -+ static HANDLE std_key = (HANDLE)-1; -+ -+ if (std_key == (HANDLE)-1) -+ std_key = open_user_reg_key( DllRedirectsW ); -+ -+ return std_key; -+} -+ -+ -+/*************************************************************************** -+ * get_redirect_app_key -+ * -+ * Get the registry key for the app-specific DllRedirects list. -+ */ -+static HANDLE get_redirect_app_key( const WCHAR *app_name ) -+{ -+ static const WCHAR DllRedirectsW[] = {'\\','D','l','l','R','e','d','i','r','e','c','t','s',0}; -+ static HANDLE app_key = (HANDLE)-1; -+ -+ if (app_key == (HANDLE)-1) -+ app_key = open_app_reg_key( DllRedirectsW, app_name ); -+ - return app_key; - } - - - /*************************************************************************** -- * get_registry_value -+ * get_registry_string - * -- * Load the registry loadorder value for a given module. -+ * Load a registry string for a given module. - */ --static enum loadorder get_registry_value( HANDLE hkey, const WCHAR *module ) -+static WCHAR* get_registry_string( HANDLE hkey, const WCHAR *module, BYTE *buffer, -+ ULONG size ) - { - UNICODE_STRING valueW; -- char buffer[80]; - DWORD count; -+ WCHAR *ret = NULL; - - RtlInitUnicodeString( &valueW, module ); -- -- if (!NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, -- buffer, sizeof(buffer), &count )) -+ if (size >= sizeof(WCHAR) && -+ !NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation, -+ buffer, size - sizeof(WCHAR), &count )) - { -- WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data; -- return parse_load_order( str ); -+ KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buffer; -+ ret = (WCHAR *)info->Data; -+ ret[info->DataLength / sizeof(WCHAR)] = 0; - } -- return LO_INVALID; -+ -+ return ret; -+} -+ -+ -+/*************************************************************************** -+ * get_registry_load_order -+ * -+ * Load the registry loadorder value for a given module. -+ */ -+static enum loadorder get_registry_load_order( HANDLE hkey, const WCHAR *module ) -+{ -+ BYTE buffer[81]; -+ WCHAR *str = get_registry_string( hkey, module, buffer, sizeof(buffer) ); -+ return str ? parse_load_order( str ) : LO_INVALID; - } - - -@@ -407,13 +470,13 @@ static enum loadorder get_load_order_value( HANDLE std_key, HANDLE app_key, cons - return ret; - } - -- if (app_key && ((ret = get_registry_value( app_key, module )) != LO_INVALID)) -+ if (app_key && ((ret = get_registry_load_order( app_key, module )) != LO_INVALID)) - { - TRACE( "got app defaults %s for %s\n", debugstr_loadorder(ret), debugstr_w(module) ); - return ret; - } - -- if (std_key && ((ret = get_registry_value( std_key, module )) != LO_INVALID)) -+ if (std_key && ((ret = get_registry_load_order( std_key, module )) != LO_INVALID)) - { - TRACE( "got standard key %s for %s\n", debugstr_loadorder(ret), debugstr_w(module) ); - return ret; -@@ -424,24 +487,44 @@ static enum loadorder get_load_order_value( HANDLE std_key, HANDLE app_key, cons - - - /*************************************************************************** -- * get_load_order (internal) -+ * get_redirect_value - * -- * Return the loadorder of a module. -- * The system directory and '.dll' extension is stripped from the path. -+ * Get the redirect value for the exact specified module string, looking in: -+ * 1. The per-application DllRedirects key -+ * 2. The standard DllRedirects key - */ --enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) -+static WCHAR* get_redirect_value( HANDLE std_key, HANDLE app_key, const WCHAR *module, -+ BYTE *buffer, ULONG size ) - { -- enum loadorder ret = LO_INVALID; -- HANDLE std_key, app_key = 0; -- WCHAR *module, *basename; -- UNICODE_STRING path_str; -- int len; -+ WCHAR *ret = NULL; - -- if (!init_done) init_load_order(); -- std_key = get_standard_key(); -- if (app_name) app_key = get_app_key( app_name ); -+ if (app_key && (ret = get_registry_string( app_key, module, buffer, size ))) -+ { -+ TRACE( "got app defaults %s for %s\n", debugstr_w(ret), debugstr_w(module) ); -+ return ret; -+ } - -- TRACE("looking for %s\n", debugstr_w(path)); -+ if (std_key && (ret = get_registry_string( std_key, module, buffer, size ))) -+ { -+ TRACE( "got standard key %s for %s\n", debugstr_w(ret), debugstr_w(module) ); -+ return ret; -+ } -+ -+ return ret; -+} -+ -+ -+/*************************************************************************** -+ * get_module_basename -+ * -+ * Determine the module basename. The caller is responsible for releasing -+ * the memory. -+ */ -+static WCHAR* get_module_basename( const WCHAR *path, WCHAR **basename ) -+{ -+ UNICODE_STRING path_str; -+ WCHAR *module; -+ int len; - - /* Strip path information if the module resides in the system directory - */ -@@ -453,12 +536,36 @@ enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) - if (!strchrW( p, '\\' ) && !strchrW( p, '/' )) path = p; - } - -- if (!(len = strlenW(path))) return ret; -- if (!(module = RtlAllocateHeap( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) ))) return ret; -+ if (!(len = strlenW(path))) return NULL; -+ if (!(module = RtlAllocateHeap( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) ))) return NULL; - strcpyW( module+1, path ); /* reserve module[0] for the wildcard char */ -- basename = (WCHAR *)get_basename( module+1 ); -+ *basename = (WCHAR *)get_basename( module+1 ); - - if (len >= 4) remove_dll_ext( module + 1 + len - 4 ); -+ return module; -+} -+ -+ -+/*************************************************************************** -+ * get_load_order (internal) -+ * -+ * Return the loadorder of a module. -+ * The system directory and '.dll' extension is stripped from the path. -+ */ -+enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) -+{ -+ enum loadorder ret = LO_INVALID; -+ HANDLE std_key, app_key = 0; -+ WCHAR *module, *basename; -+ -+ if (!init_done) init_load_order(); -+ std_key = get_override_standard_key(); -+ if (app_name) app_key = get_override_app_key( app_name ); -+ -+ TRACE("looking up loadorder for %s\n", debugstr_w(path)); -+ -+ if (!(module = get_module_basename(path, &basename))) -+ return ret; - - /* first explicit module name */ - if ((ret = get_load_order_value( std_key, app_key, module+1 )) != LO_INVALID) -@@ -489,3 +596,46 @@ enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) - RtlFreeHeap( GetProcessHeap(), 0, module ); - return ret; - } -+ -+ -+/*************************************************************************** -+ * get_redirect (internal) -+ * -+ * Return the redirect value of a module. -+ * The system directory and '.dll' extension is stripped from the path. -+ */ -+WCHAR* get_redirect( const WCHAR *app_name, const WCHAR *path, BYTE *buffer, ULONG size ) -+{ -+ WCHAR *ret = NULL; -+ HANDLE std_key, app_key = 0; -+ WCHAR *module, *basename; -+ -+ std_key = get_redirect_standard_key(); -+ if (app_name) app_key = get_redirect_app_key( app_name ); -+ -+ TRACE("looking up redirection for %s\n", debugstr_w(path)); -+ -+ if (!(module = get_module_basename(path, &basename))) -+ return ret; -+ -+ /* first explicit module name */ -+ if ((ret = get_redirect_value( std_key, app_key, module+1, buffer, size ))) -+ goto done; -+ -+ /* then module basename preceded by '*' */ -+ basename[-1] = '*'; -+ if ((ret = get_redirect_value( std_key, app_key, basename-1, buffer, size ))) -+ goto done; -+ -+ /* then module basename without '*' (only if explicit path) */ -+ if (basename != module+1 && (ret = get_redirect_value( std_key, app_key, basename, buffer, size ))) -+ goto done; -+ -+ /* and last the hard-coded default */ -+ ret = NULL; -+ TRACE( "no redirection found for %s\n", debugstr_w(path) ); -+ -+ done: -+ RtlFreeHeap( GetProcessHeap(), 0, module ); -+ return ret; -+} -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index cbd19db..e522464 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -205,6 +205,7 @@ enum loadorder - }; - - extern enum loadorder get_load_order( const WCHAR *app_name, const WCHAR *path ) DECLSPEC_HIDDEN; -+extern WCHAR* get_redirect( const WCHAR *app_name, const WCHAR *path, BYTE *buffer, ULONG size ) DECLSPEC_HIDDEN; - - struct debug_info - { -diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c -index 6bc4fb3..b0024a0 100644 ---- a/dlls/winex11.drv/init.c -+++ b/dlls/winex11.drv/init.c -@@ -365,6 +365,7 @@ static INT X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_d - { - struct x11drv_escape_get_drawable *data = out_data; - data->drawable = physDev->drawable; -+ data->dc_rect = physDev->dc_rect; - return TRUE; - } - break; -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 2694d23..3e94b64 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -292,6 +292,7 @@ struct x11drv_escape_get_drawable - Drawable drawable; /* X drawable */ - Drawable gl_drawable; /* GL drawable */ - int pixel_format; /* internal GL pixel format */ -+ RECT dc_rect; /* DC rectangle relative to drawable */ - }; - - struct x11drv_escape_flush_gl_drawable -diff --git a/programs/winecfg/Makefile.in b/programs/winecfg/Makefile.in -index 7b52a69..c86fdd0 100644 ---- a/programs/winecfg/Makefile.in -+++ b/programs/winecfg/Makefile.in -@@ -11,6 +11,7 @@ C_SRCS = \ - driveui.c \ - libraries.c \ - main.c \ -+ staging.c \ - theme.c \ - winecfg.c \ - x11drvdlg.c -diff --git a/programs/winecfg/main.c b/programs/winecfg/main.c -index b8a85fe..de209a9 100644 ---- a/programs/winecfg/main.c -+++ b/programs/winecfg/main.c -@@ -58,7 +58,7 @@ PropSheetCallback (HWND hWnd, UINT uMsg, LPARAM lParam) - return 0; - } - --#define NUM_PROPERTY_PAGES 7 -+#define NUM_PROPERTY_PAGES 8 - - static INT_PTR - doPropertySheet (HINSTANCE hInstance, HWND hOwner) -@@ -139,6 +139,16 @@ doPropertySheet (HINSTANCE hInstance, HWND hOwner) - psp[pg].lParam = 0; - pg++; - -+ psp[pg].dwSize = sizeof (PROPSHEETPAGEW); -+ psp[pg].dwFlags = PSP_USETITLE; -+ psp[pg].hInstance = hInstance; -+ psp[pg].u.pszTemplate = MAKEINTRESOURCEW (IDD_STAGING); -+ psp[pg].u2.pszIcon = NULL; -+ psp[pg].pfnDlgProc = StagingDlgProc; -+ psp[pg].pszTitle = load_string (IDS_TAB_STAGING); -+ psp[pg].lParam = 0; -+ pg++; -+ - /* - * Fill out the (General) PROPSHEETPAGE data structure - * for the property sheet -diff --git a/programs/winecfg/resource.h b/programs/winecfg/resource.h -index 8604fb4..201e5c3 100644 ---- a/programs/winecfg/resource.h -+++ b/programs/winecfg/resource.h -@@ -45,6 +45,7 @@ - #define IDS_SHELL_FOLDER 16 - #define IDS_LINKS_TO 17 - #define IDS_WINECFG_TITLE_APP 18 /* App specific title */ -+#define IDS_TAB_STAGING 19 - #define IDI_WINECFG 100 - #define IDI_LOGO 102 - #define IDD_ABOUTCFG 107 -@@ -54,6 +55,7 @@ - #define IDD_DLLCFG 111 - #define IDD_DRIVECFG 112 - #define IDD_DESKTOP_INTEGRATION 115 -+#define IDD_STAGING 116 - #define IDC_WINVER 1012 - #define IDC_DESKTOP_WIDTH 1023 - #define IDC_DESKTOP_HEIGHT 1024 -@@ -218,3 +220,6 @@ - #define IDC_ABT_TITLE_TEXT 8436 - #define IDC_ABT_WEB_LINK 8437 - #define IDC_ABT_LICENSE_TEXT 8438 -+ -+/* Staging tab */ -+#define IDC_ENABLE_NATIVE_D3D9 9001 -diff --git a/programs/winecfg/staging.c b/programs/winecfg/staging.c -new file mode 100644 -index 0000000..4a53815 ---- /dev/null -+++ b/programs/winecfg/staging.c -@@ -0,0 +1,93 @@ -+/* -+ * WineCfg Staging panel -+ * -+ * Copyright 2014 Michael Müller -+ * Copyright 2015 Sebastian Lackner -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ * -+ */ -+ -+#define COBJMACROS -+ -+#include "config.h" -+ -+#include <windows.h> -+#include <wine/unicode.h> -+#include <wine/debug.h> -+ -+#include "resource.h" -+#include "winecfg.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(winecfg); -+ -+/* -+ * Gallium nine -+ */ -+static BOOL nine_get(void) -+{ -+ BOOL ret; -+ char *value = get_reg_key(config_key, keypath("DllRedirects"), "d3d9", NULL); -+ ret = (value && !strcmp(value, "d3d9-nine.dll")); -+ HeapFree(GetProcessHeap(), 0, value); -+ return ret; -+} -+ -+static void nine_set(BOOL status) -+{ -+ set_reg_key(config_key, keypath("DllRedirects"), "d3d9", status ? "d3d9-nine.dll" : NULL); -+} -+ -+ -+static void load_staging_settings(HWND dialog) -+{ -+ CheckDlgButton(dialog, IDC_ENABLE_NATIVE_D3D9, nine_get() ? BST_CHECKED : BST_UNCHECKED); -+#if !defined(SONAME_D3DADAPTER9) -+ disable(IDC_ENABLE_NATIVE_D3D9); -+#endif -+} -+ -+INT_PTR CALLBACK StagingDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -+{ -+ switch (uMsg) -+ { -+ case WM_INITDIALOG: -+ break; -+ -+ case WM_NOTIFY: -+ if (((LPNMHDR)lParam)->code == PSN_SETACTIVE) -+ load_staging_settings(hDlg); -+ break; -+ -+ case WM_SHOWWINDOW: -+ set_window_title(hDlg); -+ break; -+ -+ case WM_DESTROY: -+ break; -+ -+ case WM_COMMAND: -+ if (HIWORD(wParam) != BN_CLICKED) break; -+ switch (LOWORD(wParam)) -+ { -+ case IDC_ENABLE_NATIVE_D3D9: -+ nine_set(IsDlgButtonChecked(hDlg, IDC_ENABLE_NATIVE_D3D9) == BST_CHECKED); -+ SendMessageW(GetParent(hDlg), PSM_CHANGED, 0, 0); -+ return TRUE; -+ } -+ break; -+ } -+ return FALSE; -+} -diff --git a/programs/winecfg/winecfg.h b/programs/winecfg/winecfg.h -index 110856a..a949474 100644 ---- a/programs/winecfg/winecfg.h -+++ b/programs/winecfg/winecfg.h -@@ -87,6 +87,7 @@ INT_PTR CALLBACK AppDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) - INT_PTR CALLBACK LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - INT_PTR CALLBACK AudioDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - INT_PTR CALLBACK ThemeDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -+INT_PTR CALLBACK StagingDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - INT_PTR CALLBACK AboutDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - - /* Drive management */ -diff --git a/programs/winecfg/winecfg.rc b/programs/winecfg/winecfg.rc -index 221916b..ee4c55d 100644 ---- a/programs/winecfg/winecfg.rc -+++ b/programs/winecfg/winecfg.rc -@@ -39,6 +39,7 @@ BEGIN - IDS_TAB_GRAPHICS "Graphics" - IDS_TAB_DESKTOP_INTEGRATION "Desktop Integration" - IDS_TAB_AUDIO "Audio" -+ IDS_TAB_STAGING "Staging" - IDS_TAB_ABOUT "About" - IDS_WINECFG_TITLE "Wine configuration" - IDS_WINECFG_TITLE_APP "Wine configuration for %s" -@@ -308,6 +309,15 @@ BEGIN - PUSHBUTTON "B&rowse...",IDC_BROWSE_SFPATH,195,195,50,13,WS_DISABLED - END - -+IDD_STAGING DIALOG 0, 0, 260, 220 -+STYLE WS_CHILD | WS_DISABLED -+FONT 8, "MS Shell Dlg" -+BEGIN -+ GROUPBOX "Staging settings",IDC_STATIC,8,4,244,210 -+ LTEXT "The following settings are experimental and may break stuff!\nMake sure to reset them again in case of a problem.\nGallium Nine requires MESA graphic drivers and AMD/Nvidia GPU.\n",IDC_STATIC,16,16,230,24 -+ CONTROL "Enable &Gallium Nine for better D3D9 graphic performance.",IDC_ENABLE_NATIVE_D3D9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,40,230,8 -+END -+ - LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL - - /* @makedep: winecfg.ico */ |