Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions native~/displayxr_xrprovider/displayxr_provider_gfx_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,21 @@ dxr_pvk_destroy(void)
s_pvk.api.vkDestroyFence(s_pvk.device, s_pvk.copy_fence, NULL);
if (s_pvk.cmd_pool && s_pvk.api.vkDestroyCommandPool)
s_pvk.api.vkDestroyCommandPool(s_pvk.device, s_pvk.cmd_pool, NULL);
s_pvk.copy_fence = VK_NULL_HANDLE;
s_pvk.cmd_pool = VK_NULL_HANDLE;

// NOT the device or the instance (DisplayXR/displayxr-runtime#1779): we made
// them through XR_KHR_vulkan_enable2 and the session still runs on them. The
// runtime's repaint thread keeps presenting the last frame on that device
// until xrEndSession; destroying it here crashed every session stop / quit
// in vkQueuePresentKHR. dxr_pvk_destroy_device() runs after xrDestroySession.
pvk_log("[DisplayXR-PROV-VK] session objects destroyed (device kept until xrDestroySession)\n");
}

void
dxr_pvk_destroy_device(void)
{
if (s_pvk.device && s_pvk.api.vkDeviceWaitIdle) s_pvk.api.vkDeviceWaitIdle(s_pvk.device);
if (s_pvk.device && s_pvk.api.vkDestroyDevice)
s_pvk.api.vkDestroyDevice(s_pvk.device, NULL);
if (s_pvk.instance && s_pvk.api.vkDestroyInstance)
Expand Down
13 changes: 10 additions & 3 deletions native~/displayxr_xrprovider/displayxr_provider_gfx_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ int dxr_pvk_create_device(XrInstance instance, XrSystemId system_id,

/// Fill an XrGraphicsBindingVulkan2KHR for xrCreateSession, chaining `next`
/// (the win32 window binding). Returns a pointer to storage owned by this TU,
/// valid until dxr_pvk_destroy(). NULL if the device was never created.
/// valid until dxr_pvk_destroy_device(). NULL if the device was never created.
const void *dxr_pvk_session_binding(const void *next);

/// Adopt Unity's Vulkan objects, captured from IUnityGraphicsVulkan by
Expand Down Expand Up @@ -206,10 +206,17 @@ int dxr_pvk_overlay_copy_to_swapchain_image(int kind, uint32_t image_index);
/// Drop the overlay's bridge and swapchain images (layer resize / teardown).
void dxr_pvk_overlay_destroy(int kind);

/// Tear down every Vulkan object this TU owns (bridges, semaphores, command
/// pool, device, instance). Safe to call when nothing was created.
/// Tear down the per-session objects (bridges, overlays, fence, command pool).
/// Call BEFORE xrEndSession. Leaves the device and instance alive: the session
/// still runs on them (DisplayXR/displayxr-runtime#1779). Safe to call when
/// nothing was created.
void dxr_pvk_destroy(void);

/// Destroy the VkDevice + VkInstance made through XR_KHR_vulkan_enable2. Call
/// only AFTER xrDestroySession: the runtime's compositor (its repaint thread
/// included) uses them until then. Safe to call when nothing was created.
void dxr_pvk_destroy_device(void);

/// 1 once dxr_pvk_create_device() has succeeded.
int dxr_pvk_device_ready(void);

Expand Down
12 changes: 9 additions & 3 deletions native~/displayxr_xrprovider/displayxr_provider_session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ extern "C" void *dxr_pvk_unity_image_ptr(int eye);
extern "C" int dxr_pvk_copy_to_swapchain_image(int eye, uint32_t image_index);
extern "C" void dxr_pvk_signal_unity_done(void);
extern "C" void dxr_pvk_destroy(void);
extern "C" void dxr_pvk_destroy_device(void);
extern "C" int dxr_pvk_device_ready(void);
// 2D overlay layers (#336). Kinds match DXR_PVK_OVERLAY_* in the VK header.
#define PS_PVK_OVERLAY_LOCAL2D 0
Expand Down Expand Up @@ -5060,14 +5061,19 @@ void dxr_prov_session_stop(void)
ps_probe_cleanup(); // weave-to-texture PROBE shared texture + handle (experiment)
if (s_ps.swapchain && s_ps.pfn_destroy_swapchain) s_ps.pfn_destroy_swapchain(s_ps.swapchain);
#if defined(ENABLE_VULKAN)
// Vulkan (#247/#249): drop the bridges BEFORE xrDestroySession — the bridge images live
// on the session device, which the runtime tears down with the session. Unity's own
// objects are only dereferenced, never destroyed. No-op on the D3D paths.
// Vulkan (#247/#249): drop the bridges BEFORE xrDestroySession, while their device is
// still current for the session. Unity's own objects are only dereferenced, never
// destroyed. No-op on the D3D paths.
if (s_ps.graphics_api == DXR_GFX_VULKAN) dxr_pvk_destroy();
#endif
if (s_ps.session && s_ps.session_ready && s_ps.pfn_end_session) s_ps.pfn_end_session(s_ps.session);
if (s_ps.session && s_ps.pfn_destroy_session) s_ps.pfn_destroy_session(s_ps.session);
if (s_ps.instance && s_ps.pfn_destroy_instance) s_ps.pfn_destroy_instance(s_ps.instance);
#if defined(ENABLE_VULKAN)
// ...and the enable2 device + instance only now: the runtime's compositor, repaint
// thread included, uses them until the session is gone (DisplayXR/displayxr-runtime#1779).
if (s_ps.graphics_api == DXR_GFX_VULKAN) dxr_pvk_destroy_device();
#endif

#ifdef _WIN32
// Bridge + cross-device fence + own-device resources.
Expand Down
Loading