diff --git a/README.md b/README.md index 4a933004..05f2a176 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,9 @@ Wine. All those differences are also documented on the Included bug fixes and improvements =================================== -**Bugfixes and features included in the next upcoming release [22]:** +**Bugfixes and features included in the next upcoming release [23]:** +* Add nvapi stubs required for GPU PhysX support * Add stub for D3DXComputeNormalMap * Add stub for D3DXComputeTangentFrameEx ([Wine Bug #31984](https://bugs.winehq.org/show_bug.cgi?id=31984)) * Add stub for D3DXIntersect diff --git a/debian/changelog b/debian/changelog index 18101fc8..74a61ae9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -30,6 +30,7 @@ wine-staging (1.7.34) UNRELEASED; urgency=low * Added patch to fix parameters for ConvertToIndexedBlendedMesh stub. * Added patch for basic CUDA support. * Added patches for D3DXComputeNormals and D3DXComputeNormalMap. + * Added patch for nvapi stubs (required for GPU PhysX support). * Removed patch to emulate write to CR4 register (accepted upstream). * Removed patch with stub for KeSetSystemAffinityThread (accepted upstream). * Removed patch to implement combase HSTRING objects (accepted upstream). diff --git a/patches/Makefile b/patches/Makefile index a290fb00..f92a13a4 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -89,6 +89,7 @@ PATCHLIST := \ ntoskrnl-Emulator.ok \ ntoskrnl-Irp_Status.ok \ ntoskrnl-Stub_FileObject.ok \ + nvapi-Stub_DLL.ok \ nvcuda-CUDA_Support.ok \ ole32-CoWaitForMultipleHandles.ok \ quartz-MediaSeeking_Positions.ok \ @@ -1398,6 +1399,19 @@ ntoskrnl-Stub_FileObject.ok: echo '+ { "Sebastian Lackner", "ntoskrnl: Initialize irp.Tail.Overlay.OriginalFileObject with stub file object.", 1 },'; \ ) > ntoskrnl-Stub_FileObject.ok +# Patchset nvapi-Stub_DLL +# | +# | Modified files: +# | * configure.ac, dlls/nvapi/Makefile.in, dlls/nvapi/nvapi.c, dlls/nvapi/nvapi.spec, dlls/nvapi/tests/Makefile.in, +# | dlls/nvapi/tests/nvapi.c, dlls/nvapi64/Makefile.in, dlls/nvapi64/nvapi64.spec, include/Makefile.in, include/nvapi.h +# | +.INTERMEDIATE: nvapi-Stub_DLL.ok +nvapi-Stub_DLL.ok: nvcuda-CUDA_Support.ok + $(call APPLY_FILE,nvapi-Stub_DLL/0001-nvapi-First-implementation.patch) + @( \ + echo '+ { "Michael Müller", "nvapi: First implementation.", 1 },'; \ + ) > nvapi-Stub_DLL.ok + # Patchset nvcuda-CUDA_Support # | # | Modified files: diff --git a/patches/nvapi-Stub_DLL/0001-nvapi-First-implementation.patch b/patches/nvapi-Stub_DLL/0001-nvapi-First-implementation.patch new file mode 100644 index 00000000..11f7f4da --- /dev/null +++ b/patches/nvapi-Stub_DLL/0001-nvapi-First-implementation.patch @@ -0,0 +1,928 @@ +From 645fe9f2724f45ccbf259e3622393bba5fc44743 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michael=20M=C3=BCller?= +Date: Mon, 5 Jan 2015 18:11:53 +0100 +Subject: nvapi: First implementation. + +--- + configure.ac | 3 + + dlls/nvapi/Makefile.in | 4 + + dlls/nvapi/nvapi.c | 462 +++++++++++++++++++++++++++++++++++++++++++ + dlls/nvapi/nvapi.spec | 5 + + dlls/nvapi/tests/Makefile.in | 5 + + dlls/nvapi/tests/nvapi.c | 265 +++++++++++++++++++++++++ + dlls/nvapi64/Makefile.in | 5 + + dlls/nvapi64/nvapi64.spec | 5 + + include/Makefile.in | 1 + + include/nvapi.h | 74 +++++++ + 10 files changed, 829 insertions(+) + create mode 100644 dlls/nvapi/Makefile.in + create mode 100644 dlls/nvapi/nvapi.c + create mode 100644 dlls/nvapi/nvapi.spec + create mode 100644 dlls/nvapi/tests/Makefile.in + create mode 100644 dlls/nvapi/tests/nvapi.c + create mode 100644 dlls/nvapi64/Makefile.in + create mode 100644 dlls/nvapi64/nvapi64.spec + create mode 100644 include/nvapi.h + +diff --git a/configure.ac b/configure.ac +index 43c33bf..efc143a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3125,6 +3125,9 @@ WINE_CONFIG_TEST(dlls/ntdsapi/tests) + WINE_CONFIG_DLL(ntoskrnl.exe,,[implib]) + WINE_CONFIG_DLL(ntprint) + WINE_CONFIG_TEST(dlls/ntprint/tests) ++WINE_CONFIG_DLL(nvapi) ++WINE_CONFIG_TEST(dlls/nvapi/tests) ++WINE_CONFIG_DLL(nvapi64,enable_win64) + WINE_CONFIG_DLL(nvcuda) + WINE_CONFIG_TEST(dlls/nvcuda/tests) + WINE_CONFIG_DLL(objsel,,[clean]) +diff --git a/dlls/nvapi/Makefile.in b/dlls/nvapi/Makefile.in +new file mode 100644 +index 0000000..606177f +--- /dev/null ++++ b/dlls/nvapi/Makefile.in +@@ -0,0 +1,4 @@ ++MODULE = nvapi.dll ++ ++C_SRCS = \ ++ nvapi.c +diff --git a/dlls/nvapi/nvapi.c b/dlls/nvapi/nvapi.c +new file mode 100644 +index 0000000..1741a48 +--- /dev/null ++++ b/dlls/nvapi/nvapi.c +@@ -0,0 +1,462 @@ ++/* ++ * Copyright (C) 2015 Michael Müller ++ * Copyright (C) 2015 Sebastian Lackner ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#include "config.h" ++ ++#include ++ ++#include "windef.h" ++#include "winbase.h" ++#include "winternl.h" ++#include "wine/debug.h" ++#include "wine/list.h" ++#include "nvapi.h" ++#include "d3d9.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(nvapi); ++ ++#if defined(__i386__) || defined(__x86_64__) ++ ++static NvAPI_Status CDECL unimplemented_stub(unsigned int offset) ++{ ++ FIXME("function 0x%x is unimplemented!\n", offset); ++ return NVAPI_ERROR; ++} ++ ++#ifdef __i386__ ++ ++#include "pshpack1.h" ++struct thunk ++{ ++ unsigned char push_ebp; ++ unsigned short mov_esp_ebp; ++ unsigned char sub_0x08_esp[3]; ++ unsigned char mov_dword_esp[3]; ++ unsigned int offset; ++ unsigned char mov_eax; ++ void *stub; ++ unsigned short call_eax; ++ unsigned char leave; ++ unsigned char ret; ++}; ++#include "poppack.h" ++ ++static void* prepare_thunk(struct thunk *thunk, unsigned int offset) ++{ ++ thunk->push_ebp = 0x55; ++ thunk->mov_esp_ebp = 0xE589; ++ thunk->sub_0x08_esp[0] = 0x83; ++ thunk->sub_0x08_esp[1] = 0xEC; ++ thunk->sub_0x08_esp[2] = 0x08; ++ thunk->mov_dword_esp[0] = 0xC7; ++ thunk->mov_dword_esp[1] = 0x04; ++ thunk->mov_dword_esp[2] = 0x24; ++ thunk->offset = offset; ++ thunk->mov_eax = 0xB8; ++ thunk->stub = &unimplemented_stub; ++ thunk->call_eax = 0xD0FF; ++ thunk->leave = 0xC9; ++ thunk->ret = 0xC3; ++ return thunk; ++} ++ ++#else ++ ++#include "pshpack1.h" ++struct thunk ++{ ++ unsigned short mov_rcx; ++ unsigned int offset; ++ unsigned int zero; ++ unsigned short mov_rax; ++ void *stub; ++ unsigned short jmp_rax; ++}; ++#include "poppack.h" ++ ++static void* prepare_thunk(struct thunk *thunk, unsigned int offset) ++{ ++ thunk->mov_rcx = 0xB948; ++ thunk->offset = offset; ++ thunk->zero = 0; ++ thunk->mov_rax = 0xB848; ++ thunk->stub = &unimplemented_stub; ++ thunk->jmp_rax = 0xE0FF; ++ return thunk; ++} ++ ++#endif ++ ++struct thunk_entry ++{ ++ struct list entry; ++ int num_thunks; ++ struct thunk thunks[0]; ++}; ++ ++static struct list unimplemented_thunks = LIST_INIT( unimplemented_thunks ); ++static SYSTEM_BASIC_INFORMATION system_info; ++ ++static RTL_CRITICAL_SECTION unimplemented_thunk_section; ++static RTL_CRITICAL_SECTION_DEBUG critsect_debug = ++{ ++ 0, 0, &unimplemented_thunk_section, ++ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, ++ 0, 0, { (DWORD_PTR)(__FILE__ ": unimplemented_thunk_section") } ++}; ++static RTL_CRITICAL_SECTION unimplemented_thunk_section = { &critsect_debug, -1, 0, 0, 0, 0 }; ++ ++static void* lookup_thunk_function(unsigned int offset) ++{ ++ struct list *ptr; ++ unsigned int i; ++ ++ /* check for existing thunk */ ++ LIST_FOR_EACH( ptr, &unimplemented_thunks ) ++ { ++ struct thunk_entry *entry = LIST_ENTRY( ptr, struct thunk_entry, entry ); ++ for (i = 0; i < entry->num_thunks; i++) ++ if (entry->thunks[i].offset == offset) ++ return &entry->thunks[i]; ++ } ++ ++ return NULL; ++} ++ ++static void* allocate_thunk_function(unsigned int offset) ++{ ++ struct thunk_entry *entry; ++ struct list *ptr; ++ ++ /* append after last existing thunk if possible */ ++ if ((ptr = list_tail( &unimplemented_thunks ))) ++ { ++ entry = LIST_ENTRY( ptr, struct thunk_entry, entry ); ++ if (FIELD_OFFSET( struct thunk_entry, thunks[entry->num_thunks + 1] ) <= system_info.PageSize) ++ return prepare_thunk( &entry->thunks[entry->num_thunks++], offset ); ++ } ++ ++ /* allocate a new block */ ++ entry = VirtualAlloc( NULL, system_info.PageSize, MEM_COMMIT | MEM_RESERVE, ++ PAGE_EXECUTE_READWRITE ); ++ if (entry) ++ { ++ list_add_tail( &unimplemented_thunks, &entry->entry ); ++ entry->num_thunks = 1; ++ return prepare_thunk( &entry->thunks[0], offset ); ++ } ++ ++ return NULL; ++} ++ ++static void* get_thunk_function(unsigned int offset) ++{ ++ void *ret; ++ TRACE("(%x)\n", offset); ++ ++ EnterCriticalSection( &unimplemented_thunk_section ); ++ ret = lookup_thunk_function( offset ); ++ if (!ret) ret = allocate_thunk_function( offset ); ++ LeaveCriticalSection( &unimplemented_thunk_section ); ++ return ret; ++} ++ ++static void init_thunks(void) ++{ ++ NtQuerySystemInformation( SystemBasicInformation, &system_info, sizeof(system_info), NULL ); ++ /* we assume here that system_info.PageSize will always be great enough to hold at least one thunk */ ++} ++ ++static void free_thunks(void) ++{ ++ struct list *ptr, *ptr2; ++ EnterCriticalSection( &unimplemented_thunk_section ); ++ LIST_FOR_EACH_SAFE( ptr, ptr2, &unimplemented_thunks ) ++ { ++ struct thunk_entry *entry = LIST_ENTRY( ptr, struct thunk_entry, entry ); ++ list_remove( ptr ); ++ VirtualFree( entry, 0, MEM_RELEASE ); ++ } ++ LeaveCriticalSection( &unimplemented_thunk_section ); ++} ++ ++#else ++ ++static NvAPI_Status CDECL unimplemented_stub() ++{ ++ FIXME("function is unimplemented!\n"); ++ return NVAPI_ERROR; ++} ++ ++static void* get_thunk_function(unsigned int offset) ++{ ++ TRACE("(%x)\n", offset); ++ return &unimplemented_stub; ++} ++ ++static void init_thunks(void) ++{ ++ /* unimplemented */ ++} ++ ++static void free_thunks(void) ++{ ++ /* unimplemented */ ++} ++ ++#endif ++ ++ ++static NvAPI_Status CDECL NvAPI_Initialize(void) ++{ ++ TRACE("()\n"); ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_Unknown1(NV_UNKNOWN_1 *param) ++{ ++ TRACE("(%p)\n", param); ++ ++ if (!param) ++ return NVAPI_INVALID_ARGUMENT; ++ ++ if (param->version != NV_UNKNOWN_1_VER) ++ return NVAPI_INCOMPATIBLE_STRUCT_VERSION; ++ ++ param->unknown1 = 1; ++ param->gpuHandle = (void *)0xdead0001; ++ param->unknown2 = 11; ++ ++ memset(param->zeros, 0, sizeof(param->zeros)); ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_Unknown2(NvPhysicalGpuHandle gpuHandle, NvPhysicalGpuHandle *retHandle) ++{ ++ TRACE("(%p, %p)\n", gpuHandle, retHandle); ++ ++ if (!gpuHandle) ++ return NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE; ++ ++ if (!retHandle) ++ return NVAPI_INVALID_ARGUMENT; ++ ++ if (gpuHandle == (void *)0xdead0001) ++ *retHandle = (void *)gpuHandle; ++ else ++ { ++ FIXME("invalid handle: %p\n", gpuHandle); ++ *retHandle = (void*)0xffffffff; ++ } ++ ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_Unknown3(NvPhysicalGpuHandle gpuHandle, NvPhysicalGpuHandle *retHandle) ++{ ++ TRACE("(%p, %p)\n", gpuHandle, retHandle); ++ ++ if (!gpuHandle || !retHandle) ++ return NVAPI_INVALID_ARGUMENT; ++ ++ if (gpuHandle == (void *)0xdead0001) ++ *retHandle = (void *)gpuHandle; ++ else ++ { ++ FIXME("invalid handle: %p\n", gpuHandle); ++ *retHandle = (void *)0xffffffff; ++ } ++ ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_GetDisplayDriverVersion(NvDisplayHandle hNvDisplay, NV_DISPLAY_DRIVER_VERSION *pVersion) ++{ ++ NvAPI_ShortString build_str = {'r','3','3','7','_','0','0','-','1','8','9',0}; ++ NvAPI_ShortString adapter = {'G','e','F','o','r','c','e',' ','9','9','9',' ','G','T','X', 0}; ++ /* TODO: find a good way to get the graphic card name, EnumDisplayDevices is useless in Wine */ ++ /* For now we return the non existing GeForce 999 GTX as graphic card name */ ++ ++ TRACE("(%p, %p)\n", hNvDisplay, pVersion); ++ ++ if (hNvDisplay && hNvDisplay != (void *)0xdead0002) ++ { ++ FIXME("invalid display handle: %p\n", hNvDisplay); ++ return NVAPI_INVALID_HANDLE; ++ } ++ ++ if (!pVersion) ++ return NVAPI_INVALID_ARGUMENT; ++ ++ pVersion->drvVersion = 33788; ++ pVersion->bldChangeListNum = 0; ++ memcpy(pVersion->szBuildBranchString, build_str, sizeof(build_str)); ++ memcpy(pVersion->szAdapterString, adapter, sizeof(adapter)); ++ ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_GetAssociatedNvidiaDisplayHandle(const char *szDisplayName, NvDisplayHandle *pNvDispHandle) ++{ ++ TRACE("(%s, %p)\n", szDisplayName, pNvDispHandle); ++ ++ *pNvDispHandle = (void *)0xdead0002; ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_GetPhysicalGPUsFromDisplay(NvDisplayHandle hNvDisp, NvPhysicalGpuHandle nvGPUHandle[NVAPI_MAX_PHYSICAL_GPUS], NvU32 *pGpuCount) ++{ ++ TRACE("(%p, %p, %p)\n", hNvDisp, nvGPUHandle, pGpuCount); ++ ++ nvGPUHandle[0] = (void *)0xdead0003; ++ *pGpuCount = 1; ++ ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_Disable(void) ++{ ++ TRACE("()\n"); ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_IsEnabled(NvU8 *pIsStereoEnabled) ++{ ++ TRACE("(%p)\n", pIsStereoEnabled); ++ ++ *pIsStereoEnabled = 0; ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_CreateHandleFromIUnknown(void *pDevice, StereoHandle *pStereoHandle) ++{ ++ TRACE("(%p, %p)\n", pDevice, pStereoHandle); ++ return NVAPI_STEREO_NOT_INITIALIZED; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_DestroyHandle(StereoHandle stereoHandle) ++{ ++ TRACE("(%p)\n", stereoHandle); ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_Activate(StereoHandle stereoHandle) ++{ ++ TRACE("(%p)\n", stereoHandle); ++ return NVAPI_STEREO_NOT_INITIALIZED; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_Deactivate(StereoHandle stereoHandle) ++{ ++ TRACE("(%p)\n", stereoHandle); ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_IsActivated(StereoHandle stereoHandle, NvU8 *pIsStereoOn) ++{ ++ TRACE("(%p, %p)\n", stereoHandle, pIsStereoOn); ++ ++ *pIsStereoOn = 0; ++ return NVAPI_OK; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_GetSeparation(StereoHandle stereoHandle, float *pSeparationPercentage) ++{ ++ TRACE("(%p, %p)\n", stereoHandle, pSeparationPercentage); ++ return NVAPI_STEREO_NOT_INITIALIZED; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_SetSeparation(StereoHandle stereoHandle, float newSeparationPercentage) ++{ ++ TRACE("(%p, %f)\n", stereoHandle, newSeparationPercentage); ++ return NVAPI_STEREO_NOT_INITIALIZED; ++} ++ ++static NvAPI_Status CDECL NvAPI_Stereo_Enable(void) ++{ ++ TRACE("()\n"); ++ return NVAPI_STEREO_NOT_INITIALIZED; ++} ++ ++static NvAPI_Status CDECL NvAPI_D3D9_StretchRectEx(IDirect3DDevice9 *pDevice, IDirect3DResource9 *pSourceResource, ++ const RECT *pSourceRect, IDirect3DResource9 *pDestResource, ++ const RECT *pDestRect, D3DTEXTUREFILTERTYPE Filter) ++{ ++ TRACE("(%p, %p, %p, %p, %p, %d)\n", pDevice, pSourceResource, pSourceRect, pDestResource, pDestRect, Filter); ++ return NVAPI_UNREGISTERED_RESOURCE; ++} ++ ++void* CDECL nvapi_QueryInterface(unsigned int offset) ++{ ++ static const struct ++ { ++ unsigned int offset; ++ void *function; ++ } ++ function_list[] = ++ { ++ {0x0150E828, NvAPI_Initialize}, ++ {0xF951A4D1, NvAPI_GetDisplayDriverVersion}, ++ {0x5786cc6e, NvAPI_Unknown1}, ++ {0x6533ea3e, NvAPI_Unknown2}, ++ {0x5380ad1a, NvAPI_Unknown3}, ++ {0x35c29134, NvAPI_GetAssociatedNvidiaDisplayHandle}, ++ {0x34ef9506, NvAPI_GetPhysicalGPUsFromDisplay}, ++ {0x2ec50c2b, NvAPI_Stereo_Disable}, ++ {0x348ff8e1, NvAPI_Stereo_IsEnabled}, ++ {0xac7e37f4, NvAPI_Stereo_CreateHandleFromIUnknown}, ++ {0x3a153134, NvAPI_Stereo_DestroyHandle}, ++ {0xf6a1ad68, NvAPI_Stereo_Activate}, ++ {0x2d68de96, NvAPI_Stereo_Deactivate}, ++ {0x1fb0bc30, NvAPI_Stereo_IsActivated}, ++ {0x451f2134, NvAPI_Stereo_GetSeparation}, ++ {0x5c069fa3, NvAPI_Stereo_SetSeparation}, ++ {0x239c4545, NvAPI_Stereo_Enable}, ++ {0xaeaecd41, NvAPI_D3D9_StretchRectEx} ++ }; ++ unsigned int i; ++ TRACE("(%x)\n", offset); ++ ++ for (i = 0; i < sizeof(function_list) / sizeof(function_list[0]); i++) ++ { ++ if (function_list[i].offset == offset) ++ return function_list[i].function; ++ } ++ ++ return get_thunk_function(offset); ++} ++ ++BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) ++{ ++ TRACE("(%p, %u, %p)\n", instance, reason, reserved); ++ switch (reason) ++ { ++ case DLL_WINE_PREATTACH: ++ return TRUE; /* prefer native version */ ++ case DLL_PROCESS_ATTACH: ++ DisableThreadLibraryCalls(instance); ++ init_thunks(); ++ break; ++ case DLL_PROCESS_DETACH: ++ free_thunks(); ++ break; ++ } ++ ++ return TRUE; ++} +diff --git a/dlls/nvapi/nvapi.spec b/dlls/nvapi/nvapi.spec +new file mode 100644 +index 0000000..f0c054b +--- /dev/null ++++ b/dlls/nvapi/nvapi.spec +@@ -0,0 +1,5 @@ ++@ cdecl nvapi_QueryInterface(long) ++@ stub DllCanUnloadNow ++@ stub DllGetClassObject ++@ stub DllRegisterServer ++@ stub DllUnregisterServer +diff --git a/dlls/nvapi/tests/Makefile.in b/dlls/nvapi/tests/Makefile.in +new file mode 100644 +index 0000000..a94df01 +--- /dev/null ++++ b/dlls/nvapi/tests/Makefile.in +@@ -0,0 +1,5 @@ ++TESTDLL = nvapi.dll ++IMPORTS = user32 shlwapi ++ ++C_SRCS = \ ++ nvapi.c +diff --git a/dlls/nvapi/tests/nvapi.c b/dlls/nvapi/tests/nvapi.c +new file mode 100644 +index 0000000..0e0fd2a +--- /dev/null ++++ b/dlls/nvapi/tests/nvapi.c +@@ -0,0 +1,265 @@ ++/* ++ * Copyright (C) 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 ++ * 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 "wingdi.h" ++#include "winuser.h" ++#include "shlwapi.h" ++#include "winerror.h" ++#include "nvapi.h" ++ ++#include "wine/test.h" ++ ++#define NvAPI_Initialize_Offset 0x0150E828 ++#define NvAPI_GetDisplayDriverVersion_Offset 0xF951A4D1 ++#define NvAPI_unknown1_Offset 0x5786cc6e ++#define NvAPI_unknown2_Offset 0x6533ea3e ++#define NvAPI_unknown3_Offset 0x5380ad1a ++ ++static void* (CDECL *pnvapi_QueryInterface)(unsigned int offset); ++static NvAPI_Status (CDECL *pNvAPI_Initialize)(void); ++static NvAPI_Status (CDECL *pNvAPI_GetDisplayDriverVersion)(NvDisplayHandle hNvDisplay, NV_DISPLAY_DRIVER_VERSION *pVersion); ++static NvAPI_Status (CDECL *pNvAPI_unknown1)(void* param0); ++static NvAPI_Status (CDECL *pNvAPI_unknown2)(NvPhysicalGpuHandle gpuHandle, void *param1); ++static NvAPI_Status (CDECL *pNvAPI_unknown3)(void *param0, void *param1); ++ ++static BOOL init(void) ++{ ++ #ifdef __x86_64__ ++ HMODULE nvapi = LoadLibraryA("nvapi64.dll"); ++ #else ++ HMODULE nvapi = LoadLibraryA("nvapi.dll"); ++ #endif ++ ++ if (!nvapi) ++ { ++ skip("Could not load nvapi.dll\n"); ++ return FALSE; ++ } ++ ++ pnvapi_QueryInterface = (void *)GetProcAddress(nvapi, "nvapi_QueryInterface"); ++ if (!pnvapi_QueryInterface) ++ { ++ win_skip("Failed to get entry point for nvapi_QueryInterface.\n"); ++ return FALSE; ++ } ++ ++ pNvAPI_Initialize = pnvapi_QueryInterface(NvAPI_Initialize_Offset); ++ pNvAPI_GetDisplayDriverVersion = pnvapi_QueryInterface(NvAPI_GetDisplayDriverVersion_Offset); ++ pNvAPI_unknown1 = pnvapi_QueryInterface(NvAPI_unknown1_Offset); ++ pNvAPI_unknown2 = pnvapi_QueryInterface(NvAPI_unknown2_Offset); ++ pNvAPI_unknown3 = pnvapi_QueryInterface(NvAPI_unknown3_Offset); ++ ++ if (!pNvAPI_Initialize) ++ { ++ win_skip("Failed to get entry point for NvAPI_Initialize.\n"); ++ return FALSE; ++ } ++ ++ if (pNvAPI_Initialize()) ++ { ++ skip("Failed to initialize nvapi.\n"); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static void test_GetDisplayDriverVersion(void) ++{ ++ NV_DISPLAY_DRIVER_VERSION version; ++ NvAPI_Status status; ++ DISPLAY_DEVICEA dinfo; ++ char *gpuName; ++ ++ if (!pNvAPI_GetDisplayDriverVersion) ++ { ++ win_skip("NvAPI_GetDisplayDriverVersion export not found.\n"); ++ return; ++ } ++ ++ status = pNvAPI_GetDisplayDriverVersion(0, NULL); ++ ok(status == NVAPI_INVALID_ARGUMENT, "Expected status NVAPI_INVALID_ARGUMENT, got %d\n", status); ++ ++ memset(&version, 0, sizeof(version)); ++ version.version = NV_DISPLAY_DRIVER_VERSION_VER; ++ ++ status = pNvAPI_GetDisplayDriverVersion((void *)0xdeadbeef, &version); ++ ok(status == NVAPI_INVALID_HANDLE, "Expected status NVAPI_INVALID_HANDLE, got %d\n", status); ++ ++ memset(&dinfo, 0, sizeof(dinfo)); ++ dinfo.cb = sizeof(dinfo); ++ ok(EnumDisplayDevicesA(NULL, 0, &dinfo, 0), "Failed to get monitor info\n"); ++ ++ trace("Device name: %s\n", (char*)&dinfo.DeviceName); ++ trace("Device string: %s\n", (char*)&dinfo.DeviceString); ++ ++ gpuName = (char*)&dinfo.DeviceString; ++ StrTrimA(gpuName, " \t\r\n"); ++ ++ if (!strncmp(gpuName, "NVIDIA ", 7)) ++ gpuName += 7; ++ ++ memset(&version, 0, sizeof(version)); ++ version.version = NV_DISPLAY_DRIVER_VERSION_VER; ++ ++ status = pNvAPI_GetDisplayDriverVersion(0, &version); ++ ok(!status, "Expected status NVAPI_OK, got %d\n", status); ++ ++ trace("Driver version: %u\n", (unsigned int)version.drvVersion); ++ trace("Change list num: %u\n", (unsigned int)version.bldChangeListNum); ++ trace("Build string: %s\n", version.szBuildBranchString); ++ trace("Adapter string: %s\n", version.szAdapterString); ++ ++ todo_wine ok(!strcmp(version.szAdapterString, gpuName), "Expected device name %s, got %s\n", ++ gpuName, version.szAdapterString); ++} ++ ++static void test_unknown1(void) ++{ ++ NV_UNKNOWN_1 test; ++ NvAPI_Status status; ++ ++ if (!pNvAPI_unknown1) ++ { ++ win_skip("pNvAPI_unknown1 export not found.\n"); ++ return; ++ } ++ ++ status = pNvAPI_unknown1(NULL); ++ ok(status == NVAPI_INVALID_ARGUMENT, "Expected status NVAPI_INVALID_ARGUMENT, got %d\n", status); ++ ++ memset(&test, 0, sizeof(test)); ++ test.version = NV_UNKNOWN_1_VER; ++ status = pNvAPI_unknown1(&test); ++ ++ ok(!status, "Expected status NVAPI_OK, got %d\n", status); ++ ok(test.unknown1 == 1, "Expected unknown1 == 1, got %d\n", test.unknown1); ++ ok(test.gpuHandle != NULL, "Expected gpuHandle != 0, got %p\n", test.gpuHandle); ++ ok(test.unknown2 == 11, "Expected unknown2 == 11, got %d\n", test.unknown2); ++} ++ ++static void test_unknown2(void) ++{ ++ NV_UNKNOWN_1 test; ++ NvAPI_Status status; ++ NvPhysicalGpuHandle test2 = NULL; ++ ++ if (!pNvAPI_unknown1) ++ { ++ win_skip("pNvAPI_unknown1 export not found.\n"); ++ return; ++ } ++ ++ if (!pNvAPI_unknown2) ++ { ++ win_skip("pNvAPI_unknown1 export not found.\n"); ++ return; ++ } ++ ++ status = pNvAPI_unknown2(NULL, NULL); ++ ok(status == NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE, "Expected status NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE, got %d\n", status); ++ ++ memset(&test, 0, sizeof(test)); ++ test.version = NV_UNKNOWN_1_VER; ++ status = pNvAPI_unknown1(&test); ++ ok(!status, "Expected status NVAPI_OK, got %d\n", status); ++ ++ status = pNvAPI_unknown2(test.gpuHandle, NULL); ++ ok(status == NVAPI_INVALID_ARGUMENT, "Expected status NVAPI_INVALID_ARGUMENT, got %d\n", status); ++ ++ status = pNvAPI_unknown2(NULL, &test2); ++ ok(status == NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE, "Expected status NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE, got %d\n", status); ++ ++ test2 = NULL; ++ status = pNvAPI_unknown2((void *)0xdeadbeef, &test2); ++ ok(!status, "Expected status NVAPI_OK, got %d\n", status); ++ ok(test2 == (void*)0xffffffff, "Expected handle 0xffffffff, got %p\n", test2); ++ ++ test2 = NULL; ++ status = pNvAPI_unknown2(test.gpuHandle, &test2); ++ ok(!status, "Expected status NVAPI_OK, got %d\n", status); ++ ok(test2 == test.gpuHandle, "Expected handle %p, got %p\n", test.gpuHandle, test2); ++} ++ ++static void test_unknown3(void) ++{ ++ NV_UNKNOWN_1 test; ++ NvAPI_Status status; ++ NvPhysicalGpuHandle test2 = NULL; ++ NvPhysicalGpuHandle test3 = NULL; ++ ++ if (!pNvAPI_unknown1) ++ { ++ win_skip("pNvAPI_unknown1 export not found.\n"); ++ return; ++ } ++ ++ if (!pNvAPI_unknown2) ++ { ++ win_skip("pNvAPI_unknown1 export not found.\n"); ++ return; ++ } ++ ++ if (!pNvAPI_unknown3) ++ { ++ win_skip("pNvAPI_unknown1 export not found.\n"); ++ return; ++ } ++ ++ status = pNvAPI_unknown3(NULL, NULL); ++ ok(status == NVAPI_INVALID_ARGUMENT, "Expected status NVAPI_INVALID_ARGUMENT, got %d\n", status); ++ ++ memset(&test, 0, sizeof(test)); ++ test.version = NV_UNKNOWN_1_VER; ++ status = pNvAPI_unknown1(&test); ++ ok(!status, "Expected status NVAPI_OK, got %d\n", status); ++ ++ status = pNvAPI_unknown2(test.gpuHandle, &test2); ++ ok(!status, "Expected status NVAPI_OK, got %d\n", status); ++ ++ status = pNvAPI_unknown3(test2, NULL); ++ ok(status == NVAPI_INVALID_ARGUMENT, "Expected status NVAPI_INVALID_ARGUMENT, got %d\n", status); ++ ++ status = pNvAPI_unknown3(NULL, &test3); ++ ok(status == NVAPI_INVALID_ARGUMENT, "Expected status NVAPI_INVALID_ARGUMENT, got %d\n", status); ++ ++ test3 = NULL; ++ status = pNvAPI_unknown3((void *)0xdeadbeef, &test3); ++ ok(!status, "Expected status NVAPI_OK, got %d\n", status); ++ ok(test3 == (void*)0xffffffff, "Expected handle 0xffffffff, got %p\n", test3); ++ ++ test3 = NULL; ++ status = pNvAPI_unknown3(test2, &test3); ++ ok(!status, "Expected status NVAPI_OK, got %d\n", status); ++ ok(test2 == test3, "Expected handle %p, got %p\n", test2, test3); ++} ++ ++START_TEST( nvapi ) ++{ ++ if (!init()) ++ return; ++ ++ test_GetDisplayDriverVersion(); ++ test_unknown1(); ++ test_unknown2(); ++ test_unknown3(); ++} +diff --git a/dlls/nvapi64/Makefile.in b/dlls/nvapi64/Makefile.in +new file mode 100644 +index 0000000..80e2d6b +--- /dev/null ++++ b/dlls/nvapi64/Makefile.in +@@ -0,0 +1,5 @@ ++MODULE = nvapi64.dll ++PARENTSRC = ../nvapi ++ ++C_SRCS = \ ++ nvapi.c +diff --git a/dlls/nvapi64/nvapi64.spec b/dlls/nvapi64/nvapi64.spec +new file mode 100644 +index 0000000..f0c054b +--- /dev/null ++++ b/dlls/nvapi64/nvapi64.spec +@@ -0,0 +1,5 @@ ++@ cdecl nvapi_QueryInterface(long) ++@ stub DllCanUnloadNow ++@ stub DllGetClassObject ++@ stub DllRegisterServer ++@ stub DllUnregisterServer +diff --git a/include/Makefile.in b/include/Makefile.in +index afd4a21..5f3798a 100644 +--- a/include/Makefile.in ++++ b/include/Makefile.in +@@ -476,6 +476,7 @@ SRCDIR_INCLUDES = \ + ntsecapi.h \ + ntsecpkg.h \ + ntstatus.h \ ++ nvapi.h \ + objbase.h \ + objsel.h \ + odbcinst.h \ +diff --git a/include/nvapi.h b/include/nvapi.h +new file mode 100644 +index 0000000..1980895 +--- /dev/null ++++ b/include/nvapi.h +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 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 ++ * 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_NVAPI_H ++#define __WINE_NVAPI_H ++ ++#include "pshpack8.h" ++ ++typedef unsigned char NvU8; ++typedef unsigned int NvU32; ++ ++#define NvAPI_Status int ++ ++#define NVAPI_OK 0 ++#define NVAPI_ERROR -1 ++#define NVAPI_INVALID_ARGUMENT -5 ++#define NVAPI_INVALID_HANDLE -8 ++#define NVAPI_INCOMPATIBLE_STRUCT_VERSION -9 ++#define NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE -101 ++#define NVAPI_STEREO_NOT_INITIALIZED -140 ++#define NVAPI_UNREGISTERED_RESOURCE -170 ++ ++#define NVAPI_SHORT_STRING_MAX 64 ++#define NVAPI_MAX_PHYSICAL_GPUS 64 ++ ++typedef char NvAPI_ShortString[NVAPI_SHORT_STRING_MAX]; ++ ++#define MAKE_NVAPI_VERSION(type,version) (NvU32)(sizeof(type) | ((version)<<16)) ++ ++typedef void *NvPhysicalGpuHandle; ++typedef void *NvDisplayHandle; ++typedef void *StereoHandle; ++ ++typedef struct ++{ ++ NvU32 version; ++ NvU32 drvVersion; ++ NvU32 bldChangeListNum; ++ NvAPI_ShortString szBuildBranchString; ++ NvAPI_ShortString szAdapterString; ++} NV_DISPLAY_DRIVER_VERSION; ++ ++#define NV_DISPLAY_DRIVER_VERSION_VER MAKE_NVAPI_VERSION(NV_DISPLAY_DRIVER_VERSION, 1) ++ ++/* undocumented stuff */ ++typedef struct ++{ ++ NvU32 version; ++ NvU32 unknown1; ++ NvPhysicalGpuHandle gpuHandle; ++ NvU32 unknown2; ++ void* zeros[14]; ++}NV_UNKNOWN_1; ++ ++#define NV_UNKNOWN_1_VER MAKE_NVAPI_VERSION(NV_UNKNOWN_1, 1) ++ ++#include "poppack.h" ++ ++#endif /* __WINE_NVAPI_H */ +-- +1.9.1 + diff --git a/patches/nvapi-Stub_DLL/definition b/patches/nvapi-Stub_DLL/definition new file mode 100644 index 00000000..d569b704 --- /dev/null +++ b/patches/nvapi-Stub_DLL/definition @@ -0,0 +1,2 @@ +Fixes: Add nvapi stubs required for GPU PhysX support +Depends: nvcuda-CUDA_Support