vrclient: Read Vulkan instance extensions from registry in load_vrclient().

CW-Bug-Id: #24553
CW-Bug-Id: #24891
This commit is contained in:
Paul Gofman 2025-05-27 19:44:17 -06:00
parent 0142040ba9
commit bfeda97e32
3 changed files with 104 additions and 86 deletions

View File

@ -31,6 +31,8 @@ CREATE_TYPE_INFO_VTABLE;
struct compositor_data compositor_data = {0};
static BOOL vrclient_loaded;
char *g_instance_extensions;
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
{
TRACE("(%p, %lu, %p)\n", instance, reason, reserved);
@ -64,6 +66,91 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
return TRUE;
}
static BOOL get_vulkan_extensions_from_registry(void)
{
DWORD type, value, size = sizeof(value), wait_result;
LSTATUS status;
HANDLE event;
HKEY vr_key;
DWORD len;
if ((status = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\Wine\\VR", 0, KEY_READ, &vr_key )))
{
ERR( "Could not create key, status %#lx.\n", status );
return FALSE;
}
if ((status = RegQueryValueExA( vr_key, "state", NULL, &type, (BYTE *)&value, &size )))
{
ERR( "Could not query VR state, status %#lx\n", status );
RegCloseKey( vr_key );
return FALSE;
}
if (type != REG_DWORD)
{
ERR( "Invalid VR state type: %lx\n", type );
RegCloseKey( vr_key );
return FALSE;
}
if (!value)
{
event = CreateEventA( NULL, FALSE, FALSE, NULL );
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 %#lx\n", status );
break;
}
if (value) break;
while ((wait_result = WaitForSingleObject( event, 1000 )) == WAIT_TIMEOUT)
WARN( "Waiting for VR to become ready\n" );
if (wait_result != WAIT_OBJECT_0)
{
ERR( "Wait for VR state change failed\n" );
break;
}
}
CloseHandle( event );
}
if (value != 1)
{
RegCloseKey( vr_key );
return FALSE;
}
if ((status = RegQueryValueExA( vr_key, "openvr_vulkan_instance_extensions", NULL, &type, NULL, &len )))
{
ERR( "Could not query openvr vulkan instance extensions, status %#lx\n", status );
RegCloseKey( vr_key );
return FALSE;
}
if (!(g_instance_extensions = malloc(len)))
{
RegCloseKey( vr_key );
return FALSE;
}
if ((status = RegQueryValueExA( vr_key, "openvr_vulkan_instance_extensions", NULL, &type,
(BYTE *)g_instance_extensions, &len )))
{
ERR( "Error getting openvr_vulkan_instance_extensions, status %#lx.\n", status );
RegCloseKey( vr_key );
return FALSE;
}
RegCloseKey( vr_key );
return TRUE;
}
static BOOL array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
{
SIZE_T max_capacity, new_capacity;
@ -107,7 +194,7 @@ struct w_iface *create_win_interface( const char *name, struct u_iface u_iface )
return NULL;
}
static int load_vrclient(void)
static int load_vrclient( BOOL initializing_registry )
{
struct vrclient_init_params params = {.winevulkan = LoadLibraryW( L"winevulkan.dll" )};
WCHAR pathW[PATH_MAX];
@ -123,6 +210,12 @@ static int load_vrclient(void)
if (vrclient_loaded) return 1;
if (!(initializing_registry || get_vulkan_extensions_from_registry()))
{
TRACE( "Error getting extensions from registry.\n" );
return 0;
}
/* PROTON_VR_RUNTIME is provided by the proton setup script */
if(!GetEnvironmentVariableW(L"PROTON_VR_RUNTIME", pathW, ARRAY_SIZE(pathW)))
{
@ -184,7 +277,7 @@ void * __stdcall HmdSystemFactory(const char *name, int *return_code)
{
struct vrclient_HmdSystemFactory_params params = {.name = name, .return_code = return_code};
TRACE("name: %s, return_code: %p\n", name, return_code);
if (!load_vrclient()) return NULL;
if (!load_vrclient( FALSE )) return NULL;
VRCLIENT_CALL( vrclient_HmdSystemFactory, &params );
return create_win_interface( name, params._ret );
}
@ -193,7 +286,7 @@ void * __stdcall VRClientCoreFactory(const char *name, int *return_code)
{
struct vrclient_VRClientCoreFactory_params params = {.name = name, .return_code = return_code};
TRACE("name: %s, return_code: %p\n", name, return_code);
if (!load_vrclient()) return NULL;
if (!load_vrclient( FALSE )) return NULL;
VRCLIENT_CALL( vrclient_VRClientCoreFactory, &params );
return create_win_interface( name, params._ret );
}
@ -288,7 +381,7 @@ BOOL CDECL vrclient_init_registry(void)
return FALSE;
}
if (!load_vrclient())
if (!load_vrclient( TRUE ))
{
TRACE( "Failed to load vrclient\n" );
set_vr_status( vr_key, -1 );

View File

@ -112,6 +112,8 @@ struct generic_interface
void (*dtor)(struct w_iface *);
};
extern char *g_instance_extensions;
#ifdef __dxvk_interop_h__
extern w_Texture_t vrclient_translate_texture_dxvk( const w_Texture_t *texture, w_VRVulkanTextureData_t *vkdata,
IDXGIVkInteropSurface *dxvk_surface, IDXGIVkInteropDevice **p_dxvk_device,

View File

@ -3,57 +3,6 @@
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 %lx\n", status);
return FALSE;
}
if (type != REG_DWORD)
{
ERR("Invalid VR state type: %lx\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 %lx\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( HMODULE winevulkan, uint32_t *texture_type, VkInstance *instance )
{
/* OpenVR IVRSystem::GetOutputDevice requires a VkInstance if textureType is Vulkan,
@ -62,11 +11,9 @@ VkResult fixup_get_output_device_pre( HMODULE winevulkan, uint32_t *texture_type
PFN_vkGetInstanceProcAddr p_vkGetInstanceProcAddr;
PFN_vkCreateInstance p_vkCreateInstance;
const char **instance_extension_list;
DWORD type, len, extension_count = 0;
char *instance_extensions, *pos;
DWORD extension_count = 0;
VkResult vk_result;
LSTATUS status;
HKEY vr_key;
VkInstanceCreateInfo create_info = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
@ -75,37 +22,13 @@ VkResult fixup_get_output_device_pre( HMODULE winevulkan, uint32_t *texture_type
if (*texture_type != TextureType_DirectX && *texture_type != TextureType_DirectX12 && *texture_type != TextureType_DXGISharedHandle)
return VK_SUCCESS;
if (!g_instance_extensions)
return VK_ERROR_INITIALIZATION_FAILED;
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 %lx\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 %lx\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 %lx\n", status);
free(instance_extensions);
return VK_ERROR_INITIALIZATION_FAILED;
}
instance_extensions = strdup(g_instance_extensions);
TRACE("Creating VkInstance for IVRSystem::GetOutputDevice\n");
has_get_device_properties2 = strstr(instance_extensions, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) != NULL;