wineopenxr: Support creating a D3D12 XR instance.

This commit is contained in:
Yuxuan Shui 2024-05-09 22:29:00 +01:00 committed by Arkadiusz Hiler
parent 2cf4673153
commit ef4785f325
3 changed files with 359 additions and 11 deletions

View file

@ -28,6 +28,7 @@
#include "wine/vulkan.h"
#define VULKAN_H_ 1// tell dxvk-interop not to include vulkan.h
#include "dxvk-interop.h"
#include "vkd3d-proton-interop.h"
#undef WINE_VK_HOST
#define XR_USE_GRAPHICS_API_D3D11 1
#define XR_USE_GRAPHICS_API_D3D12 1
@ -79,6 +80,7 @@ static struct
substitute_extensions[] =
{
{"XR_KHR_D3D11_enable", "XR_KHR_vulkan_enable"},
{"XR_KHR_D3D12_enable", "XR_KHR_vulkan_enable"},
{"XR_KHR_win32_convert_performance_counter_time", "XR_KHR_convert_timespec_time", TRUE, TRUE},
};
@ -682,7 +684,6 @@ XrResult WINAPI wine_xrEnumerateInstanceExtensionProperties(const char *layerNam
else
dst = (*propertyCountOutput)++;
strcpy(properties[dst].extensionName, substitute_extensions[j].win32_ext);
break;
}
}
}
@ -790,9 +791,13 @@ XrResult WINAPI wine_xrGetD3D11GraphicsRequirementsKHR(XrInstance instance,
XrResult WINAPI wine_xrGetD3D12GraphicsRequirementsKHR(XrInstance instance,
XrSystemId systemId, XrGraphicsRequirementsD3D12KHR *graphicsRequirements)
{
WINE_FIXME("unimplemented\n");
/* FIXME */
return XR_ERROR_INITIALIZATION_FAILED;
XrGraphicsRequirementsD3D11KHR requirements;
XrResult result = wine_xrGetD3D11GraphicsRequirementsKHR(instance, systemId, &requirements);
if (result != XR_SUCCESS)
return result;
graphicsRequirements->adapterLuid = requirements.adapterLuid;
graphicsRequirements->minFeatureLevel = D3D_FEATURE_LEVEL_11_0;
return XR_SUCCESS;
}
XrResult WINAPI wine_xrGetInstanceProcAddr(XrInstance instance, const char *fn_name, PFN_xrVoidFunction *out_fn)
@ -907,6 +912,12 @@ XrResult WINAPI wine_xrDestroyInstance(XrInstance instance)
if(wine_instance->dxvk_device)
wine_instance->dxvk_device->lpVtbl->Release(wine_instance->dxvk_device);
if (wine_instance->d3d12_device)
{
wine_instance->d3d12_device->lpVtbl->Release(wine_instance->d3d12_device);
wine_instance->d3d12_queue->lpVtbl->Release(wine_instance->d3d12_queue);
}
heap_free(wine_instance);
return XR_SUCCESS;
@ -1041,6 +1052,60 @@ XrResult WINAPI wine_xrCreateSession(XrInstance instance, const XrSessionCreateI
break;
}
case XR_TYPE_GRAPHICS_BINDING_D3D12_KHR:
{
const XrGraphicsBindingD3D12KHR *their_d3d12_binding = createInfo->next;
HRESULT hr;
UINT32 queue_index;
VkQueueFlags queue_flags;
ID3D12DeviceExt1 *device_ext;
hr = ID3D12Device_QueryInterface(their_d3d12_binding->device, &IID_ID3D12DXVKInteropDevice, (void**)&wine_instance->d3d12_device);
if (FAILED(hr))
{
WINE_WARN("Given ID3D12Device doesn't support ID3D12DXVKInteropDevice. Only vkd3d-proton is supported.\n");
return XR_ERROR_VALIDATION_FAILURE;
}
hr = ID3D12Device_QueryInterface(their_d3d12_binding->device, &IID_ID3D12DeviceExt1, (void **)&device_ext);
if (FAILED(hr))
{
WINE_WARN("Given ID3D12Device doesn't support ID3D12DeviceExt1. Only vkd3d-proton is supported.\n");
return XR_ERROR_VALIDATION_FAILURE;
}
our_vk_binding.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR;
our_vk_binding.next = NULL;
wine_instance->d3d12_queue = their_d3d12_binding->queue;
their_d3d12_binding->queue->lpVtbl->AddRef(their_d3d12_binding->queue);
wine_instance->d3d12_device->lpVtbl->GetVulkanHandles(wine_instance->d3d12_device,
&our_vk_binding.instance, &our_vk_binding.physicalDevice, &our_vk_binding.device);
device_ext->lpVtbl->GetVulkanQueueInfoEx(device_ext, their_d3d12_binding->queue,
&wine_instance->vk_queue, &queue_index, &queue_flags, &our_vk_binding.queueFamilyIndex);
device_ext->lpVtbl->Release(device_ext);
wine_instance->vk_device = our_vk_binding.device = get_native_VkDevice(our_vk_binding.device);
wine_instance->vk_queue = get_native_VkQueue(wine_instance->vk_queue);
our_vk_binding.queueIndex = queue_index;
our_vk_binding.instance = get_native_VkInstance(our_vk_binding.instance);
if ((res = do_vulkan_init(wine_instance, our_vk_binding.instance)) != XR_SUCCESS)
return res;
if (wine_instance->vk_phys_dev != get_native_VkPhysicalDevice(our_vk_binding.physicalDevice))
WINE_WARN("VK physical device does not match that from xrGetVulkanGraphicsDeviceKHR.\n");
our_vk_binding.physicalDevice = wine_instance->vk_phys_dev;
our_create_info = *createInfo;
our_create_info.next = &our_vk_binding;
createInfo = &our_create_info;
session_type = SESSION_TYPE_D3D12;
break;
}
default:
WINE_WARN("Unhandled graphics binding type: %d\n", ((XrBaseInStructure *)createInfo->next)->type);
break;
@ -1572,7 +1637,7 @@ XrResult WINAPI wine_xrEnumerateSwapchainFormats(XrSession session, uint32_t for
WINE_TRACE("%p, %u, %p, %p\n", session, formatCapacityInput, formatCountOutput, formats);
if (wine_session->session_type != SESSION_TYPE_D3D11)
if (wine_session->session_type != SESSION_TYPE_D3D11 && wine_session->session_type != SESSION_TYPE_D3D12)
return xrEnumerateSwapchainFormats(wine_session->session, formatCapacityInput, formatCountOutput, formats);
res = xrEnumerateSwapchainFormats(wine_session->session, 0, &real_format_count, NULL);
@ -1620,7 +1685,7 @@ XrResult WINAPI wine_xrCreateSwapchain(XrSession session, const XrSwapchainCreat
wine_swapchain = heap_alloc_zero(sizeof(*wine_swapchain));
wine_swapchain->create_info = *createInfo;
if(wine_session->session_type == SESSION_TYPE_D3D11){
if(wine_session->session_type == SESSION_TYPE_D3D11 || wine_session->session_type == SESSION_TYPE_D3D12){
BOOL format_is_depth;
our_createInfo = *createInfo;
our_createInfo.format = map_format_dxgi_to_vulkan(createInfo->format);
@ -1656,6 +1721,18 @@ XrResult WINAPI wine_xrCreateSwapchain(XrSession session, const XrSwapchainCreat
return XR_SUCCESS;
}
static void release_d3d12_resources(wine_XrSwapchain *wine_swapchain, uint32_t image_count)
{
XrSwapchainImageD3D12KHR *d3d12_images = (XrSwapchainImageD3D12KHR *)wine_swapchain->images;
UINT i;
if (!image_count)
return;
for (i = 0; i < image_count; i++)
if (d3d12_images[i].texture)
d3d12_images[i].texture->lpVtbl->Release(d3d12_images[i].texture);
}
XrResult WINAPI wine_xrDestroySwapchain(XrSwapchain swapchain)
{
wine_XrSwapchain *wine_swapchain = (wine_XrSwapchain *)swapchain;
@ -1669,7 +1746,8 @@ XrResult WINAPI wine_xrDestroySwapchain(XrSwapchain swapchain)
XrSwapchainImageD3D11KHR *d3d11_images = (XrSwapchainImageD3D11KHR *)wine_swapchain->images;
for (i = 0; i < wine_swapchain->image_count; i++)
d3d11_images[i].texture->lpVtbl->Release(d3d11_images[i].texture);
}
} else if (wine_swapchain->wine_session->session_type == SESSION_TYPE_D3D12)
release_d3d12_resources(wine_swapchain, wine_swapchain->image_count);
heap_free(wine_swapchain->images);
wine_swapchain->image_count = 0;
}
@ -1713,10 +1791,10 @@ XrResult WINAPI wine_xrEnumerateSwapchainImages(XrSwapchain swapchain, uint32_t
XrSwapchainImageVulkanKHR *our_vk = NULL;
HRESULT hr;
size_t image_size = 0;
uint32_t i, to_copy;
uint32_t i;
WINE_TRACE("%p, %u, %p, %p\n", swapchain, imageCapacityInput, imageCountOutput, images);
if (wine_swapchain->wine_session->session_type != SESSION_TYPE_D3D11)
if (wine_swapchain->wine_session->session_type != SESSION_TYPE_D3D11 && wine_swapchain->wine_session->session_type != SESSION_TYPE_D3D12)
return xrEnumerateSwapchainImages(wine_swapchain->swapchain, imageCapacityInput, imageCountOutput, images);
if (!wine_swapchain->image_count) {
@ -1772,17 +1850,80 @@ XrResult WINAPI wine_xrEnumerateSwapchainImages(XrSwapchain swapchain, uint32_t
WINE_TRACE("Successfully allocated texture %p\n", our_d3d11[i].texture);
}
wine_swapchain->images = (XrSwapchainImageBaseHeader *)our_d3d11;
} else if(wine_swapchain->wine_session->session_type == SESSION_TYPE_D3D12){
XrSwapchainImageD3D12KHR *our_d3d12;
D3D12_RESOURCE_DESC1 desc;
ID3D12DeviceExt1 *device_ext;
HRESULT hr = wine_instance->d3d12_device->lpVtbl->QueryInterface(wine_instance->d3d12_device, &IID_ID3D12DeviceExt1, (void **)&device_ext);
BOOL format_is_depth = is_vulkan_format_depth(map_format_dxgi_to_vulkan(wine_swapchain->create_info.format));
BOOL succeeded = TRUE;
if (FAILED(hr))
{
WINE_ERR("Cannot get vkd3d-proton interface: %08x\n", hr);
return XR_ERROR_VALIDATION_FAILURE;
}
desc.Alignment = 0;
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Width = wine_swapchain->create_info.width;
desc.Height = wine_swapchain->create_info.height;
desc.MipLevels = wine_swapchain->create_info.mipCount;
desc.DepthOrArraySize = wine_swapchain->create_info.arraySize;
desc.Format = wine_swapchain->create_info.format;
WINE_TRACE("creating vkd3d-proton texture with dxgi format %d (%x)\n",
desc.Format, desc.Format);
desc.SampleDesc.Count = wine_swapchain->create_info.sampleCount;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
desc.Flags = 0;
if (!format_is_depth)
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
else
{
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
if (!(wine_swapchain->create_info.usageFlags & XR_SWAPCHAIN_USAGE_SAMPLED_BIT))
desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
}
if (wine_swapchain->create_info.usageFlags & XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT)
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
our_d3d12 = heap_alloc_zero(sizeof(XrSwapchainImageD3D12KHR) * image_count);
for(i = 0; i < image_count; ++i)
{
hr = device_ext->lpVtbl->CreateResourceFromBorrowedHandle(device_ext,
&desc, our_vk[i].image, &our_d3d12[i].texture);
if(FAILED(hr))
{
WINE_ERR("Failed to create vkd3d-proton texture from VkImage: %08x\n", hr);
succeeded = FALSE;
break;
}
WINE_TRACE("Successfully allocated texture %p\n", our_d3d12[i].texture);
}
device_ext->lpVtbl->Release(device_ext);
wine_swapchain->images = (XrSwapchainImageBaseHeader *)our_d3d12;
if (!succeeded)
{
release_d3d12_resources(wine_swapchain, image_count);
heap_free(wine_swapchain->images);
wine_swapchain->images = NULL;
heap_free(our_vk);
return XR_ERROR_RUNTIME_FAILURE;
}
}
heap_free(our_vk);
wine_swapchain->image_count = image_count;
WINE_TRACE("image count %d\n", image_count);
}
to_copy = min(wine_swapchain->image_count, imageCapacityInput);
*imageCountOutput = wine_swapchain->image_count;
if (wine_swapchain->wine_session->session_type == SESSION_TYPE_D3D11){
image_size = sizeof(XrSwapchainImageD3D11KHR);
} else if (wine_swapchain->wine_session->session_type == SESSION_TYPE_D3D12){
image_size = sizeof(XrSwapchainImageD3D12KHR);
}
memcpy(images, wine_swapchain->images, image_size * to_copy);
memcpy(images, wine_swapchain->images, image_size * min(wine_swapchain->image_count, imageCapacityInput));
return XR_SUCCESS;
}
@ -1917,6 +2058,7 @@ XrResult WINAPI wine_xrEndFrame(XrSession session, const XrFrameEndInfo *frameEn
wine_XrSession *wine_session = (wine_XrSession *)session;
uint32_t i, view_idx = 0, view_info_idx = 0;
IDXGIVkInteropDevice2 *dxvk_device;
ID3D12DXVKInteropDevice *d3d12_device;
XrFrameEndInfo our_frameEndInfo;
XrResult res;
@ -1946,9 +2088,16 @@ XrResult WINAPI wine_xrEndFrame(XrSession session, const XrFrameEndInfo *frameEn
dxvk_device->lpVtbl->FlushRenderingCommands(dxvk_device);
dxvk_device->lpVtbl->LockSubmissionQueue(dxvk_device);
}
else if ((d3d12_device = wine_session->wine_instance->d3d12_device))
{
WINE_TRACE("Locking vkd3d-proton submission queue.\n");
d3d12_device->lpVtbl->LockCommandQueue(d3d12_device, wine_session->wine_instance->d3d12_queue);
}
res = xrEndFrame(((wine_XrSession *)session)->session, &our_frameEndInfo);
if (dxvk_device)
dxvk_device->lpVtbl->ReleaseSubmissionQueue(dxvk_device);
else if (d3d12_device)
d3d12_device->lpVtbl->UnlockCommandQueue(d3d12_device, wine_session->wine_instance->d3d12_queue);
return res;
}
@ -1976,6 +2125,10 @@ XrResult WINAPI wine_xrAcquireSwapchainImage(XrSwapchain swapchain, const XrSwap
XrResult ret;
WINE_TRACE("%p, %p, %p\n", swapchain, acquireInfo, index);
if (wine_session->session_type == SESSION_TYPE_D3D12)
return XR_ERROR_RUNTIME_FAILURE;
if ((dxvk_device = wine_session->wine_instance->dxvk_device))
dxvk_device->lpVtbl->LockSubmissionQueue(dxvk_device);
ret = xrAcquireSwapchainImage(((wine_XrSwapchain *)swapchain)->swapchain, acquireInfo, index);
@ -1991,6 +2144,10 @@ XrResult WINAPI wine_xrReleaseSwapchainImage(XrSwapchain swapchain, const XrSwap
XrResult ret;
WINE_TRACE("%p, %p\n", swapchain, releaseInfo);
if (wine_session->session_type == SESSION_TYPE_D3D12)
return XR_ERROR_RUNTIME_FAILURE;
if ((dxvk_device = wine_session->wine_instance->dxvk_device))
dxvk_device->lpVtbl->LockSubmissionQueue(dxvk_device);
ret = xrReleaseSwapchainImage(((wine_XrSwapchain *)swapchain)->swapchain, releaseInfo);

View file

@ -20,6 +20,11 @@ typedef struct wine_XrInstance {
XrSystemId systemId;
IDXGIVkInteropDevice2 *dxvk_device;
ID3D12DXVKInteropDevice *d3d12_device;
ID3D12CommandQueue *d3d12_queue;
VkDevice vk_device;
VkQueue vk_queue;
} wine_XrInstance;
union CompositionLayer;

View file

@ -0,0 +1,186 @@
/*** Partially copied from autogenerated header by WIDL 6.4 from ../src-vkd3d-proton/include/vkd3d_device_vkd3d_ext.idl ***/
#pragma once
#include <d3d12.h>
#include <vulkan/vulkan.h>
#ifndef __ID3D12DeviceExt1_FWD_DEFINED__
#define __ID3D12DeviceExt1_FWD_DEFINED__
typedef interface ID3D12DeviceExt1 ID3D12DeviceExt1;
#endif
#ifndef __ID3D12DXVKInteropDevice_FWD_DEFINED__
#define __ID3D12DXVKInteropDevice_FWD_DEFINED__
typedef interface ID3D12DXVKInteropDevice ID3D12DXVKInteropDevice;
#endif
/*****************************************************************************
* ID3D12DeviceExt1 interface
*/
#ifndef __ID3D12DeviceExt1_INTERFACE_DEFINED__
#define __ID3D12DeviceExt1_INTERFACE_DEFINED__
typedef struct D3D12_UAV_INFO D3D12_UAV_INFO;
typedef struct D3D12_VK_EXTENSION D3D12_VK_EXTENSION;
typedef struct D3D12_CUBIN_DATA_HANDLE D3D12_CUBIN_DATA_HANDLE;
DEFINE_GUID(IID_ID3D12DeviceExt1, 0x099a73fd, 0x2199, 0x4f45, 0xbf,0x48, 0x0e,0xb8,0x6f,0x6f,0xdb,0x65);
typedef struct ID3D12DeviceExt1Vtbl {
BEGIN_INTERFACE
/*** IUnknown methods ***/
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
ID3D12DeviceExt1 *This,
REFIID riid,
void **object);
ULONG (STDMETHODCALLTYPE *AddRef)(
ID3D12DeviceExt1 *This);
ULONG (STDMETHODCALLTYPE *Release)(
ID3D12DeviceExt1 *This);
/*** ID3D12DeviceExt methods ***/
HRESULT (STDMETHODCALLTYPE *GetVulkanHandles)(
ID3D12DeviceExt1 *This,
VkInstance *vk_instance,
VkPhysicalDevice *vk_physical_device,
VkDevice *vk_device);
BOOL (STDMETHODCALLTYPE *GetExtensionSupport)(
ID3D12DeviceExt1 *This,
D3D12_VK_EXTENSION extension);
HRESULT (STDMETHODCALLTYPE *CreateCubinComputeShaderWithName)(
ID3D12DeviceExt1 *This,
const void *cubin_data,
UINT32 cubin_size,
UINT32 block_x,
UINT32 block_y,
UINT32 block_z,
const char *shader_name,
D3D12_CUBIN_DATA_HANDLE **handle);
HRESULT (STDMETHODCALLTYPE *DestroyCubinComputeShader)(
ID3D12DeviceExt1 *This,
D3D12_CUBIN_DATA_HANDLE *handle);
HRESULT (STDMETHODCALLTYPE *GetCudaTextureObject)(
ID3D12DeviceExt1 *This,
D3D12_CPU_DESCRIPTOR_HANDLE srv_handle,
D3D12_CPU_DESCRIPTOR_HANDLE sampler_handle,
UINT32 *cuda_texture_handle);
HRESULT (STDMETHODCALLTYPE *GetCudaSurfaceObject)(
ID3D12DeviceExt1 *This,
D3D12_CPU_DESCRIPTOR_HANDLE uav_handle,
UINT32 *cuda_surface_handle);
HRESULT (STDMETHODCALLTYPE *CaptureUAVInfo)(
ID3D12DeviceExt1 *This,
D3D12_UAV_INFO *uav_info);
/*** ID3D12DeviceExt1 methods ***/
HRESULT (STDMETHODCALLTYPE *CreateResourceFromBorrowedHandle)(
ID3D12DeviceExt1 *This,
const D3D12_RESOURCE_DESC1 *desc,
UINT64 vk_handle,
ID3D12Resource **resource);
HRESULT (STDMETHODCALLTYPE *GetVulkanQueueInfoEx)(
ID3D12DeviceExt1 *This,
ID3D12CommandQueue *queue,
VkQueue *vk_queue,
UINT32 *vk_queue_index,
UINT32 *vk_queue_flags,
UINT32 *vk_queue_family);
END_INTERFACE
} ID3D12DeviceExt1Vtbl;
interface ID3D12DeviceExt1 {
CONST_VTBL ID3D12DeviceExt1Vtbl* lpVtbl;
};
#endif
/*****************************************************************************
* ID3D12DXVKInteropDevice interface
*/
#ifndef __ID3D12DXVKInteropDevice_INTERFACE_DEFINED__
#define __ID3D12DXVKInteropDevice_INTERFACE_DEFINED__
DEFINE_GUID(IID_ID3D12DXVKInteropDevice, 0x39da4e09, 0xbd1c, 0x4198, 0x9f,0xae, 0x86,0xbb,0xe3,0xbe,0x41,0xfd);
typedef struct ID3D12DXVKInteropDeviceVtbl {
BEGIN_INTERFACE
/*** IUnknown methods ***/
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
ID3D12DXVKInteropDevice *This,
REFIID riid,
void **object);
ULONG (STDMETHODCALLTYPE *AddRef)(
ID3D12DXVKInteropDevice *This);
ULONG (STDMETHODCALLTYPE *Release)(
ID3D12DXVKInteropDevice *This);
/*** ID3D12DXVKInteropDevice methods ***/
HRESULT (STDMETHODCALLTYPE *GetDXGIAdapter)(
ID3D12DXVKInteropDevice *This,
REFIID iid,
void **object);
HRESULT (STDMETHODCALLTYPE *GetInstanceExtensions)(
ID3D12DXVKInteropDevice *This,
UINT *extension_count,
const char **extensions);
HRESULT (STDMETHODCALLTYPE *GetDeviceExtensions)(
ID3D12DXVKInteropDevice *This,
UINT *extension_count,
const char **extensions);
HRESULT (STDMETHODCALLTYPE *GetDeviceFeatures)(
ID3D12DXVKInteropDevice *This,
const VkPhysicalDeviceFeatures2 **features);
HRESULT (STDMETHODCALLTYPE *GetVulkanHandles)(
ID3D12DXVKInteropDevice *This,
VkInstance *vk_instance,
VkPhysicalDevice *vk_physical_device,
VkDevice *vk_device);
HRESULT (STDMETHODCALLTYPE *GetVulkanQueueInfo)(
ID3D12DXVKInteropDevice *This,
ID3D12CommandQueue *queue,
VkQueue *vk_queue,
UINT32 *vk_queue_family);
void (STDMETHODCALLTYPE *GetVulkanImageLayout)(
ID3D12DXVKInteropDevice *This,
ID3D12Resource *resource,
D3D12_RESOURCE_STATES state,
VkImageLayout *vk_layout);
HRESULT (STDMETHODCALLTYPE *GetVulkanResourceInfo)(
ID3D12DXVKInteropDevice *This,
ID3D12Resource *resource,
UINT64 *vk_handle,
UINT64 *buffer_offset);
HRESULT (STDMETHODCALLTYPE *LockCommandQueue)(
ID3D12DXVKInteropDevice *This,
ID3D12CommandQueue *queue);
HRESULT (STDMETHODCALLTYPE *UnlockCommandQueue)(
ID3D12DXVKInteropDevice *This,
ID3D12CommandQueue *queue);
END_INTERFACE
} ID3D12DXVKInteropDeviceVtbl;
interface ID3D12DXVKInteropDevice {
CONST_VTBL ID3D12DXVKInteropDeviceVtbl* lpVtbl;
};
#endif