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