diff --git a/vrclient_x64/cppIVRSystem_IVRSystem_016.cpp b/vrclient_x64/cppIVRSystem_IVRSystem_016.cpp index 4735da22..1c1a3b02 100644 --- a/vrclient_x64/cppIVRSystem_IVRSystem_016.cpp +++ b/vrclient_x64/cppIVRSystem_IVRSystem_016.cpp @@ -69,14 +69,6 @@ NTSTATUS IVRSystem_IVRSystem_016_GetDXGIOutputInfo( void *args ) return 0; } -NTSTATUS IVRSystem_IVRSystem_016_GetOutputDevice( void *args ) -{ - struct IVRSystem_IVRSystem_016_GetOutputDevice_params *params = (struct IVRSystem_IVRSystem_016_GetOutputDevice_params *)args; - struct u_IVRSystem_IVRSystem_016 *iface = (struct u_IVRSystem_IVRSystem_016 *)params->linux_side; - iface->GetOutputDevice( params->pnDevice, params->textureType ); - return 0; -} - NTSTATUS IVRSystem_IVRSystem_016_IsDisplayOnDesktop( void *args ) { struct IVRSystem_IVRSystem_016_IsDisplayOnDesktop_params *params = (struct IVRSystem_IVRSystem_016_IsDisplayOnDesktop_params *)args; diff --git a/vrclient_x64/gen_wrapper.py b/vrclient_x64/gen_wrapper.py index 03921898..d4e0a33f 100755 --- a/vrclient_x64/gen_wrapper.py +++ b/vrclient_x64/gen_wrapper.py @@ -234,7 +234,7 @@ MANUAL_METHODS = { "IVRClientCore_GetGenericInterface": lambda ver, abi: abi == 'w', "IVRClientCore_Cleanup": lambda ver, abi: abi == 'w', "IVRSystem_GetDXGIOutputInfo": lambda ver, abi: abi == 'w', - "IVRSystem_GetOutputDevice": lambda ver, abi: abi == 'u' and ver > 16, + "IVRSystem_GetOutputDevice": lambda ver, abi: ver > 15, "IVRCompositor_Submit": lambda ver, abi: ver > 8, "IVRCompositor_SubmitWithArrayIndex": lambda ver, abi: ver > 8, "IVRCompositor_SetSkyboxOverride": lambda ver, abi: ver > 8, diff --git a/vrclient_x64/unix_vrsystem_manual.cpp b/vrclient_x64/unix_vrsystem_manual.cpp index 4b99899d..d158f1d4 100644 --- a/vrclient_x64/unix_vrsystem_manual.cpp +++ b/vrclient_x64/unix_vrsystem_manual.cpp @@ -23,6 +23,18 @@ static uint64_t wrap_device( uint32_t type, VkInstance_T *instance, uint64_t dev return device; } +NTSTATUS IVRSystem_IVRSystem_016_GetOutputDevice( void *args ) +{ + /* hijacking IVRSystem_IVRSystem_017_GetOutputDevice_params because we need the instance for wrapping */ + struct IVRSystem_IVRSystem_017_GetOutputDevice_params *params = (struct IVRSystem_IVRSystem_017_GetOutputDevice_params *)args; + struct u_IVRSystem_IVRSystem_016 *iface = (struct u_IVRSystem_IVRSystem_016 *)params->linux_side; + uint64_t host_device; + + iface->GetOutputDevice( &host_device, params->textureType ); + *params->pnDevice = wrap_device( params->textureType, params->pInstance, host_device ); + return 0; +} + NTSTATUS IVRSystem_IVRSystem_017_GetOutputDevice( void *args ) { struct IVRSystem_IVRSystem_017_GetOutputDevice_params *params = (struct IVRSystem_IVRSystem_017_GetOutputDevice_params *)args; diff --git a/vrclient_x64/vrsystem_manual.c b/vrclient_x64/vrsystem_manual.c index 6ae2ae1a..698b69ed 100644 --- a/vrclient_x64/vrsystem_manual.c +++ b/vrclient_x64/vrsystem_manual.c @@ -1,7 +1,202 @@ #include "vrclient_private.h" +#include "winreg.h" WINE_DEFAULT_DEBUG_CHANNEL(vrclient); +static BOOL wait_vr_key_ready( HKEY vr_key ) +{ + DWORD type, value, size = sizeof(value), wait_result; + LSTATUS status; + HANDLE event; + BOOL ret; + + if ((status = RegQueryValueExA(vr_key, "state", NULL, &type, (BYTE *)&value, &size))) + { + ERR("Could not query VR state, status %x\n", status); + return FALSE; + } + if (type != REG_DWORD) + { + ERR("Invalid VR state type: %x\n", type); + return FALSE; + } + if (value) return value == 1; + + event = CreateEventA(NULL, FALSE, FALSE, NULL); + ret = FALSE; + while (1) + { + if (RegNotifyChangeKeyValue(vr_key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, event, TRUE)) + { + ERR("Error registering VR key change notification"); + break; + } + size = sizeof(value); + if ((status = RegQueryValueExA(vr_key, "state", NULL, &type, (BYTE *)&value, &size))) + { + ERR("Couild not query VR state, status %x\n", status); + break; + } + if (value) + { + ret = value == 1; + break; + } + while ((wait_result = WaitForSingleObject(event, 1000)) == WAIT_TIMEOUT) + WARN("Waiting for VR to because ready\n"); + if (wait_result != WAIT_OBJECT_0) + { + ERR("Wait for VR state change failed\n"); + break; + } + } + CloseHandle(event); + return ret; +} + +VkResult fixup_get_output_device_pre( uint32_t *texture_type, VkInstance *instance ) +{ + /* OpenVR IVRSystem::GetOutputDevice requires a VkInstance if textureType is Vulkan, + * so we create one here. */ + static const WCHAR winevulkanW[] = {'w','i','n','e','v','u','l','k','a','n','.','d','l','l',0}; + BOOL has_get_device_properties2, has_external_memory_caps; + PFN_vkGetInstanceProcAddr p_vkGetInstanceProcAddr; + HMODULE winevulkan = LoadLibraryW(winevulkanW); + PFN_vkCreateInstance p_vkCreateInstance; + const char **instance_extension_list; + DWORD type, len, extension_count = 0; + char *instance_extensions, *pos; + VkResult vk_result; + LSTATUS status; + HKEY vr_key; + + VkInstanceCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + }; + + if (*texture_type != TextureType_DirectX && *texture_type != TextureType_DirectX12 && *texture_type != TextureType_DXGISharedHandle) + return VK_SUCCESS; + + p_vkGetInstanceProcAddr = (void *)GetProcAddress(winevulkan, "vkGetInstanceProcAddr"); + p_vkCreateInstance = (void *)p_vkGetInstanceProcAddr(NULL, "vkCreateInstance"); + + if ((status = RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\VR", 0, KEY_READ, &vr_key))) + { + ERR("Failed to open OpenVR registry key, status %x\n", status); + return VK_ERROR_INITIALIZATION_FAILED; + } + if (!wait_vr_key_ready(vr_key)) + { + RegCloseKey(vr_key); + return VK_ERROR_INITIALIZATION_FAILED; + } + + if ((status = RegQueryValueExA(vr_key, "openvr_vulkan_instance_extensions", NULL, &type, NULL, &len))) + { + ERR("Could not query openvr vulkan instance extensions, status %x\n", status); + RegCloseKey(vr_key); + return VK_ERROR_INITIALIZATION_FAILED; + } + + instance_extensions = calloc(len + 1, 1); + status = RegQueryValueExA(vr_key, "openvr_vulkan_instance_extensions", NULL, &type, (BYTE *)instance_extensions, &len); + RegCloseKey(vr_key); + if (status) + { + ERR("Could not query openvr vulkan instance extensions, status %x\n", status); + free(instance_extensions); + return VK_ERROR_INITIALIZATION_FAILED; + } + + TRACE("Creating VkInstance for IVRSystem::GetOutputDevice\n"); + + has_get_device_properties2 = strstr(instance_extensions, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) != NULL; + if (!has_get_device_properties2) extension_count += 1; + has_external_memory_caps = strstr(instance_extensions, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME) != NULL; + if (!has_external_memory_caps) extension_count += 1; + for (pos = instance_extensions; *pos == ' '; pos++); + while (*pos != '\0') + { + extension_count++; + for (; *pos != ' ' && *pos != '\0'; pos++); + for (; *pos == ' '; pos++); + } + instance_extension_list = calloc(extension_count, sizeof(char *)); + + extension_count = 0; + if (!has_get_device_properties2) + instance_extension_list[extension_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; + if (!has_external_memory_caps) + instance_extension_list[extension_count++] = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME; + for (pos = instance_extensions; *pos == ' '; pos++); + while (TRUE) + { + instance_extension_list[extension_count++] = pos; + for (; *pos != ' ' && *pos != '\0'; pos++); + if (*pos == '\0') break; + *(pos++) = '\0'; + for (; *pos == ' '; pos++); + } + create_info.ppEnabledExtensionNames = instance_extension_list; + create_info.enabledExtensionCount = extension_count; + + vk_result = p_vkCreateInstance(&create_info, NULL, instance); + free(instance_extension_list); + free(instance_extensions); + if (vk_result == VK_SUCCESS) *texture_type = TextureType_Vulkan; + else ERR("Failed to create VkInstance\n"); + + return vk_result; +} + +void fixup_get_output_device_post( uint64_t *device, VkInstance *instance, uint32_t original_texture_type ) +{ + static const WCHAR winevulkanW[] = {'w','i','n','e','v','u','l','k','a','n','.','d','l','l',0}; + PFN_vkGetPhysicalDeviceProperties2 p_vkGetPhysicalDeviceProperties2; + PFN_vkGetInstanceProcAddr p_vkGetInstanceProcAddr; + HMODULE winevulkan = LoadLibraryW(winevulkanW); + PFN_vkDestroyInstance p_vkDestroyInstance; + VkPhysicalDeviceIDProperties id_props = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES, + }; + VkPhysicalDeviceProperties2 props = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = &id_props, + }; + + if ( + original_texture_type != TextureType_DirectX && + original_texture_type != TextureType_DirectX12 && + original_texture_type != TextureType_DXGISharedHandle + ) + return; + + p_vkGetInstanceProcAddr = (void *)GetProcAddress(winevulkan, "vkGetInstanceProcAddr"); + p_vkGetPhysicalDeviceProperties2 = (void *)p_vkGetInstanceProcAddr(*instance, "vkGetPhysicalDeviceProperties2"); + p_vkDestroyInstance = (void *)p_vkGetInstanceProcAddr(*instance, "vkDestroyInstance"); + + if (*device != 0) + { + p_vkGetPhysicalDeviceProperties2((VkPhysicalDevice)(intptr_t)*device, &props); + if (!id_props.deviceLUIDValid) + { + *device = 0; + WARN("VkPhysicalDevice doesn't have valid LUID\n"); + } + else + { + memcpy(device, id_props.deviceLUID, sizeof(uint8_t[8])); + TRACE("LUID for OpenVR VkPhysicalDevice is %#I64x\n", *device); + } + } + else + ERR("Failed to get output device from OpenVR runtime\n"); + + p_vkDestroyInstance(*instance, NULL); + *instance = VK_NULL_HANDLE; +} + + void __thiscall winIVRSystem_IVRSystem_003_GetDXGIOutputInfo( struct w_steam_iface *_this, int32_t *pnAdapterIndex, int32_t *pnAdapterOutputIndex ) { @@ -105,3 +300,119 @@ void __thiscall winIVRSystem_IVRSystem_022_GetDXGIOutputInfo( struct w_steam_ifa FIXME( "%p\n", _this ); *pnAdapterIndex = 0; } + +void __thiscall winIVRSystem_IVRSystem_016_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) +{ + struct IVRSystem_IVRSystem_017_GetOutputDevice_params params = + { + .linux_side = _this->u_iface, + .pnDevice = pnDevice, + .textureType = textureType, + .pInstance = pInstance, + }; + TRACE("%p\n", _this); + if (fixup_get_output_device_pre( ¶ms.textureType, ¶ms.pInstance ) != VK_SUCCESS) + { + *pnDevice = 0; + return; + } + VRCLIENT_CALL( IVRSystem_IVRSystem_016_GetOutputDevice, ¶ms ); + fixup_get_output_device_post(pnDevice, ¶ms.pInstance, textureType); +} + +void __thiscall winIVRSystem_IVRSystem_017_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) +{ + struct IVRSystem_IVRSystem_017_GetOutputDevice_params params = + { + .linux_side = _this->u_iface, + .pnDevice = pnDevice, + .textureType = textureType, + .pInstance = pInstance, + }; + TRACE("%p\n", _this); + if (fixup_get_output_device_pre( ¶ms.textureType, ¶ms.pInstance ) != VK_SUCCESS) + { + *pnDevice = 0; + return; + } + VRCLIENT_CALL( IVRSystem_IVRSystem_017_GetOutputDevice, ¶ms ); + fixup_get_output_device_post(pnDevice, ¶ms.pInstance, textureType); +} + +void __thiscall winIVRSystem_IVRSystem_019_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) +{ + struct IVRSystem_IVRSystem_019_GetOutputDevice_params params = + { + .linux_side = _this->u_iface, + .pnDevice = pnDevice, + .textureType = textureType, + .pInstance = pInstance, + }; + TRACE("%p\n", _this); + if (fixup_get_output_device_pre( ¶ms.textureType, ¶ms.pInstance ) != VK_SUCCESS) + { + *pnDevice = 0; + return; + } + VRCLIENT_CALL( IVRSystem_IVRSystem_019_GetOutputDevice, ¶ms ); + fixup_get_output_device_post(pnDevice, ¶ms.pInstance, textureType); +} + +void __thiscall winIVRSystem_IVRSystem_020_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) +{ + struct IVRSystem_IVRSystem_020_GetOutputDevice_params params = + { + .linux_side = _this->u_iface, + .pnDevice = pnDevice, + .textureType = textureType, + .pInstance = pInstance, + }; + TRACE("%p\n", _this); + if (fixup_get_output_device_pre( ¶ms.textureType, ¶ms.pInstance ) != VK_SUCCESS) + { + *pnDevice = 0; + return; + } + VRCLIENT_CALL( IVRSystem_IVRSystem_020_GetOutputDevice, ¶ms ); + fixup_get_output_device_post(pnDevice, ¶ms.pInstance, textureType); +} + +void __thiscall winIVRSystem_IVRSystem_021_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) +{ + struct IVRSystem_IVRSystem_021_GetOutputDevice_params params = + { + .linux_side = _this->u_iface, + .pnDevice = pnDevice, + .textureType = textureType, + .pInstance = pInstance, + }; + TRACE("%p\n", _this); + if (fixup_get_output_device_pre( ¶ms.textureType, ¶ms.pInstance ) != VK_SUCCESS) + { + *pnDevice = 0; + return; + } + VRCLIENT_CALL( IVRSystem_IVRSystem_021_GetOutputDevice, ¶ms ); + fixup_get_output_device_post(pnDevice, ¶ms.pInstance, textureType); +} + + +void __thiscall winIVRSystem_IVRSystem_022_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) +{ + struct IVRSystem_IVRSystem_022_GetOutputDevice_params params = + { + .linux_side = _this->u_iface, + .pnDevice = pnDevice, + .textureType = textureType, + .pInstance = pInstance, + }; + TRACE("%p\n", _this); + if (fixup_get_output_device_pre( ¶ms.textureType, ¶ms.pInstance ) != VK_SUCCESS) + { + *pnDevice = 0; + return; + } + VRCLIENT_CALL( IVRSystem_IVRSystem_022_GetOutputDevice, ¶ms ); + fixup_get_output_device_post(pnDevice, ¶ms.pInstance, textureType); +} + diff --git a/vrclient_x64/winIVRSystem.c b/vrclient_x64/winIVRSystem.c index 4d5e3759..77ae127f 100644 --- a/vrclient_x64/winIVRSystem.c +++ b/vrclient_x64/winIVRSystem.c @@ -7222,17 +7222,7 @@ int32_t __thiscall winIVRSystem_IVRSystem_016_GetD3D9AdapterIndex(struct w_steam extern void __thiscall winIVRSystem_IVRSystem_016_GetDXGIOutputInfo(struct w_steam_iface *_this, int32_t *pnAdapterIndex); -void __thiscall winIVRSystem_IVRSystem_016_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType) -{ - struct IVRSystem_IVRSystem_016_GetOutputDevice_params params = - { - .linux_side = _this->u_iface, - .pnDevice = pnDevice, - .textureType = textureType, - }; - TRACE("%p\n", _this); - VRCLIENT_CALL( IVRSystem_IVRSystem_016_GetOutputDevice, ¶ms ); -} +extern void __thiscall winIVRSystem_IVRSystem_016_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType); int8_t __thiscall winIVRSystem_IVRSystem_016_IsDisplayOnDesktop(struct w_steam_iface *_this) { @@ -7987,18 +7977,7 @@ int32_t __thiscall winIVRSystem_IVRSystem_017_GetD3D9AdapterIndex(struct w_steam extern void __thiscall winIVRSystem_IVRSystem_017_GetDXGIOutputInfo(struct w_steam_iface *_this, int32_t *pnAdapterIndex); -void __thiscall winIVRSystem_IVRSystem_017_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) -{ - struct IVRSystem_IVRSystem_017_GetOutputDevice_params params = - { - .linux_side = _this->u_iface, - .pnDevice = pnDevice, - .textureType = textureType, - .pInstance = pInstance, - }; - TRACE("%p\n", _this); - VRCLIENT_CALL( IVRSystem_IVRSystem_017_GetOutputDevice, ¶ms ); -} +extern void __thiscall winIVRSystem_IVRSystem_017_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance); int8_t __thiscall winIVRSystem_IVRSystem_017_IsDisplayOnDesktop(struct w_steam_iface *_this) { @@ -8755,18 +8734,7 @@ int32_t __thiscall winIVRSystem_IVRSystem_019_GetD3D9AdapterIndex(struct w_steam extern void __thiscall winIVRSystem_IVRSystem_019_GetDXGIOutputInfo(struct w_steam_iface *_this, int32_t *pnAdapterIndex); -void __thiscall winIVRSystem_IVRSystem_019_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) -{ - struct IVRSystem_IVRSystem_019_GetOutputDevice_params params = - { - .linux_side = _this->u_iface, - .pnDevice = pnDevice, - .textureType = textureType, - .pInstance = pInstance, - }; - TRACE("%p\n", _this); - VRCLIENT_CALL( IVRSystem_IVRSystem_019_GetOutputDevice, ¶ms ); -} +extern void __thiscall winIVRSystem_IVRSystem_019_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance); int8_t __thiscall winIVRSystem_IVRSystem_019_IsDisplayOnDesktop(struct w_steam_iface *_this) { @@ -9557,18 +9525,7 @@ int32_t __thiscall winIVRSystem_IVRSystem_020_GetD3D9AdapterIndex(struct w_steam extern void __thiscall winIVRSystem_IVRSystem_020_GetDXGIOutputInfo(struct w_steam_iface *_this, int32_t *pnAdapterIndex); -void __thiscall winIVRSystem_IVRSystem_020_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) -{ - struct IVRSystem_IVRSystem_020_GetOutputDevice_params params = - { - .linux_side = _this->u_iface, - .pnDevice = pnDevice, - .textureType = textureType, - .pInstance = pInstance, - }; - TRACE("%p\n", _this); - VRCLIENT_CALL( IVRSystem_IVRSystem_020_GetOutputDevice, ¶ms ); -} +extern void __thiscall winIVRSystem_IVRSystem_020_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance); int8_t __thiscall winIVRSystem_IVRSystem_020_IsDisplayOnDesktop(struct w_steam_iface *_this) { @@ -10369,18 +10326,7 @@ int32_t __thiscall winIVRSystem_IVRSystem_021_GetD3D9AdapterIndex(struct w_steam extern void __thiscall winIVRSystem_IVRSystem_021_GetDXGIOutputInfo(struct w_steam_iface *_this, int32_t *pnAdapterIndex); -void __thiscall winIVRSystem_IVRSystem_021_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) -{ - struct IVRSystem_IVRSystem_021_GetOutputDevice_params params = - { - .linux_side = _this->u_iface, - .pnDevice = pnDevice, - .textureType = textureType, - .pInstance = pInstance, - }; - TRACE("%p\n", _this); - VRCLIENT_CALL( IVRSystem_IVRSystem_021_GetOutputDevice, ¶ms ); -} +extern void __thiscall winIVRSystem_IVRSystem_021_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance); int8_t __thiscall winIVRSystem_IVRSystem_021_IsDisplayOnDesktop(struct w_steam_iface *_this) { @@ -11168,18 +11114,7 @@ int32_t __thiscall winIVRSystem_IVRSystem_022_GetD3D9AdapterIndex(struct w_steam extern void __thiscall winIVRSystem_IVRSystem_022_GetDXGIOutputInfo(struct w_steam_iface *_this, int32_t *pnAdapterIndex); -void __thiscall winIVRSystem_IVRSystem_022_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance) -{ - struct IVRSystem_IVRSystem_022_GetOutputDevice_params params = - { - .linux_side = _this->u_iface, - .pnDevice = pnDevice, - .textureType = textureType, - .pInstance = pInstance, - }; - TRACE("%p\n", _this); - VRCLIENT_CALL( IVRSystem_IVRSystem_022_GetOutputDevice, ¶ms ); -} +extern void __thiscall winIVRSystem_IVRSystem_022_GetOutputDevice(struct w_steam_iface *_this, uint64_t *pnDevice, uint32_t textureType, VkInstance_T *pInstance); int8_t __thiscall winIVRSystem_IVRSystem_022_IsDisplayOnDesktop(struct w_steam_iface *_this) {