From f86ca5044338b5a1b7b62c5282b296d1489a03f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Thu, 22 Sep 2016 16:56:58 +0200 Subject: [PATCH] libs/vkd3d: Create Vulkan instance when creating D3D12 device. We link directly to the Vulkan loader library and use few exported procedures. According to the documentation the loader library exports all core Vulkan procedures on Windows, Linux and Android. --- configure.ac | 6 ++ libs/vkd3d/device.c | 72 +++++++++++++++- libs/vkd3d/utils.c | 56 ++++++++++++ libs/vkd3d/vkd3d_private.h | 16 ++++ libs/vkd3d/vkd3d_vulkan.h | 58 +++++++++++++ libs/vkd3d/vulkan_procs.h | 169 +++++++++++++++++++++++++++++++++++++ 6 files changed, 375 insertions(+), 2 deletions(-) create mode 100644 libs/vkd3d/vkd3d_vulkan.h create mode 100644 libs/vkd3d/vulkan_procs.h diff --git a/configure.ac b/configure.ac index 6dd107ed..af7b87eb 100644 --- a/configure.ac +++ b/configure.ac @@ -38,6 +38,12 @@ then VKD3D_CHECK_CFLAGS([-Wvla]) fi +dnl Check for headers +AC_CHECK_HEADERS([vulkan/vulkan.h], [], [AC_MSG_ERROR([vulkan.h not found.])]) + +dnl Check for libraries +AC_CHECK_LIB([vulkan], [vkGetInstanceProcAddr], [], [AC_MSG_ERROR([libvulkan not found.])]) + dnl Check for __sync_add_and_fetch AC_MSG_CHECKING([for __sync_add_and_fetch]) AC_LINK_IFELSE( diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index e775d1d5..33afe32a 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -22,6 +22,62 @@ #include "vkd3d_private.h" +static HRESULT vkd3d_instance_init(struct vkd3d_instance *instance) +{ + VkApplicationInfo application_info; + VkInstanceCreateInfo instance_info; + VkInstance vk_instance; + VkResult vr; + HRESULT hr; + + TRACE("instance %p.\n", instance); + + application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + application_info.pNext = NULL; + application_info.pApplicationName = PACKAGE_NAME; + application_info.applicationVersion = 0; + application_info.pEngineName = NULL; + application_info.engineVersion = 0; + application_info.apiVersion = VK_API_VERSION_1_0; + + instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instance_info.pNext = NULL; + instance_info.flags = 0; + instance_info.pApplicationInfo = &application_info; + instance_info.enabledLayerCount = 0; + instance_info.ppEnabledLayerNames = NULL; + instance_info.enabledExtensionCount = 0; + instance_info.ppEnabledExtensionNames = NULL; + + if ((vr = vkCreateInstance(&instance_info, NULL, &vk_instance))) + { + ERR("Failed to create Vulkan instance, vr %d.\n", vr); + return hresult_from_vk_result(vr); + } + + if (FAILED(hr = vkd3d_load_vk_instance_procs(&instance->vk_procs, vk_instance))) + { + ERR("Failed to load instance procs, hr %#x.\n", hr); + vkDestroyInstance(vk_instance, NULL); + return hr; + } + + instance->vk_instance = vk_instance; + + TRACE("Created Vulkan instance %p.\n", vk_instance); + + return S_OK; +} + +static void vkd3d_instance_destroy(struct vkd3d_instance *instance) +{ + const struct vkd3d_vk_instance_procs *vk_procs = &instance->vk_procs; + + TRACE("instance %p.\n", instance); + + VK_CALL(vkDestroyInstance(instance->vk_instance, NULL)); +} + /* ID3D12Device */ static inline struct d3d12_device *impl_from_ID3D12Device(ID3D12Device *iface) { @@ -66,7 +122,10 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device *iface) TRACE("%p decreasing refcount to %u.\n", device, refcount); if (!refcount) + { + vkd3d_instance_destroy(&device->vkd3d_instance); vkd3d_free(device); + } return refcount; } @@ -567,20 +626,29 @@ static const struct ID3D12DeviceVtbl d3d12_device_vtbl = d3d12_device_GetAdapterLuid, }; -static void d3d12_device_init(struct d3d12_device *device) +static HRESULT d3d12_device_init(struct d3d12_device *device) { + HRESULT hr; + device->ID3D12Device_iface.lpVtbl = &d3d12_device_vtbl; device->refcount = 1; + + if (FAILED(hr = vkd3d_instance_init(&device->vkd3d_instance))) + return hr; + + return S_OK; } HRESULT d3d12_device_create(struct d3d12_device **device) { struct d3d12_device *object; + HRESULT hr; if (!(object = vkd3d_malloc(sizeof(*object)))) return E_OUTOFMEMORY; - d3d12_device_init(object); + if (FAILED(hr = d3d12_device_init(object))) + return hr; TRACE("Created device %p.\n", object); diff --git a/libs/vkd3d/utils.c b/libs/vkd3d/utils.c index f5ed1d9f..862cb124 100644 --- a/libs/vkd3d/utils.c +++ b/libs/vkd3d/utils.c @@ -67,3 +67,59 @@ HRESULT return_interface(IUnknown *iface, REFIID iface_riid, IUnknown_Release(iface); return hr; } + +HRESULT hresult_from_vk_result(VkResult vr) +{ + switch (vr) + { + case VK_SUCCESS: + return S_OK; + case VK_ERROR_OUT_OF_HOST_MEMORY: + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + return E_OUTOFMEMORY; + + default: + FIXME("Unhandled VkResult %d.\n", vr); + return E_FAIL; + } +} + +#define LOAD_INSTANCE_PFN(name) \ + if (!(procs->name = (void *)vkGetInstanceProcAddr(instance, #name))) \ + { \ + ERR("Could not get instance proc addr for '" #name "'.\n"); \ + return E_FAIL; \ + } + +HRESULT vkd3d_load_vk_instance_procs(struct vkd3d_vk_instance_procs *procs, + VkInstance instance) +{ + memset(procs, 0, sizeof(*procs)); + +#define VK_INSTANCE_PFN LOAD_INSTANCE_PFN +#include "vulkan_procs.h" + + TRACE("Loaded procs for VkInstance %p.\n", instance); + return S_OK; +} + +#define COPY_PARENT_PFN(name) procs->name = parent_procs->name; +#define LOAD_DEVICE_PFN(name) \ + if (!(procs->name = (void *)procs->vkGetDeviceProcAddr(device, #name))) \ + { \ + ERR("Could not get device proc addr for '" #name "'.\n"); \ + return E_FAIL; \ + } + +HRESULT vkd3d_load_vk_device_procs(struct vkd3d_vk_device_procs *procs, + const struct vkd3d_vk_instance_procs *parent_procs, VkDevice device) +{ + memset(procs, 0, sizeof(*procs)); + +#define VK_INSTANCE_PFN COPY_PARENT_PFN +#define VK_DEVICE_PFN LOAD_DEVICE_PFN +#include "vulkan_procs.h" + + TRACE("Loaded procs for VkDevice %p.\n", device); + return S_OK; +} diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 3b919658..762f8e15 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -26,6 +26,7 @@ #define COBJMACROS #include "vkd3d_common.h" #include "vkd3d_debug.h" +#include "vkd3d_vulkan.h" #include "d3d12.h" @@ -33,6 +34,12 @@ struct d3d12_device; +struct vkd3d_instance +{ + VkInstance vk_instance; + struct vkd3d_vk_instance_procs vk_procs; +}; + /* ID3D12CommandAllocator */ struct d3d12_command_allocator { @@ -81,6 +88,8 @@ struct d3d12_device { ID3D12Device ID3D12Device_iface; ULONG refcount; + + struct vkd3d_instance vkd3d_instance; }; HRESULT d3d12_device_create(struct d3d12_device **device) DECLSPEC_HIDDEN; @@ -113,4 +122,11 @@ static inline void vkd3d_free(void *ptr) free(ptr); } +HRESULT hresult_from_vk_result(VkResult vr) DECLSPEC_HIDDEN; + +HRESULT vkd3d_load_vk_instance_procs(struct vkd3d_vk_instance_procs *procs, + VkInstance instance) DECLSPEC_HIDDEN; +HRESULT vkd3d_load_vk_device_procs(struct vkd3d_vk_device_procs *procs, + const struct vkd3d_vk_instance_procs *parent_procs, VkDevice device) DECLSPEC_HIDDEN; + #endif /* __VKD3D_PRIVATE_H */ diff --git a/libs/vkd3d/vkd3d_vulkan.h b/libs/vkd3d/vkd3d_vulkan.h new file mode 100644 index 00000000..7c5c6854 --- /dev/null +++ b/libs/vkd3d/vkd3d_vulkan.h @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Józef Kucia for CodeWeavers + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef __VKD3D_VULKAN_H +#define __VKD3D_VULKAN_H + +#define VK_NO_PROTOTYPES +#include "vulkan/vulkan.h" + +#define DECLARE_VK_PFN(name) PFN_##name name; + +/* We link directly to the loader library and use the following exported functions. */ +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, + const char *name); +VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkInstance *instance); +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *layer_name, + uint32_t *property_count, VkExtensionProperties *properties); +VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *property_count, + VkLayerProperties *properties); +VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator); +VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *allocator); + +struct vkd3d_vk_instance_procs +{ +#define VK_INSTANCE_PFN DECLARE_VK_PFN +#include "vulkan_procs.h" +}; + +struct vkd3d_vk_device_procs +{ +#define VK_INSTANCE_PFN DECLARE_VK_PFN +#define VK_DEVICE_PFN DECLARE_VK_PFN +#include "vulkan_procs.h" +}; + +#define VK_CALL(f) (vk_procs->f) + +#endif /* __VKD3D_VULKAN_H */ diff --git a/libs/vkd3d/vulkan_procs.h b/libs/vkd3d/vulkan_procs.h new file mode 100644 index 00000000..d8841998 --- /dev/null +++ b/libs/vkd3d/vulkan_procs.h @@ -0,0 +1,169 @@ +/* + * Copyright 2016 Józef Kucia for CodeWeavers + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef VK_INSTANCE_PFN +# define VK_INSTANCE_PFN(x) +#endif + +#ifndef VK_DEVICE_PFN +# define VK_DEVICE_PFN(x) +#endif + +/* Instance functions (obtained by vkGetInstanceProcAddr). */ +VK_INSTANCE_PFN(vkCreateDevice) +VK_INSTANCE_PFN(vkDestroyInstance) +VK_INSTANCE_PFN(vkEnumerateDeviceExtensionProperties) +VK_INSTANCE_PFN(vkEnumerateDeviceLayerProperties) +VK_INSTANCE_PFN(vkEnumeratePhysicalDevices) +VK_INSTANCE_PFN(vkGetDeviceProcAddr) +VK_INSTANCE_PFN(vkGetPhysicalDeviceFeatures) +VK_INSTANCE_PFN(vkGetPhysicalDeviceFormatProperties) +VK_INSTANCE_PFN(vkGetPhysicalDeviceImageFormatProperties) +VK_INSTANCE_PFN(vkGetPhysicalDeviceMemoryProperties) +VK_INSTANCE_PFN(vkGetPhysicalDeviceProperties) +VK_INSTANCE_PFN(vkGetPhysicalDeviceQueueFamilyProperties) +VK_INSTANCE_PFN(vkGetPhysicalDeviceSparseImageFormatProperties) + +/* Device functions (obtained by vkGetDeviceProcAddr). */ +VK_DEVICE_PFN(vkAllocateCommandBuffers) +VK_DEVICE_PFN(vkAllocateDescriptorSets) +VK_DEVICE_PFN(vkAllocateMemory) +VK_DEVICE_PFN(vkBeginCommandBuffer) +VK_DEVICE_PFN(vkBindBufferMemory) +VK_DEVICE_PFN(vkBindImageMemory) +VK_DEVICE_PFN(vkCmdBeginQuery) +VK_DEVICE_PFN(vkCmdBeginRenderPass) +VK_DEVICE_PFN(vkCmdBindDescriptorSets) +VK_DEVICE_PFN(vkCmdBindIndexBuffer) +VK_DEVICE_PFN(vkCmdBindPipeline) +VK_DEVICE_PFN(vkCmdBindVertexBuffers) +VK_DEVICE_PFN(vkCmdBlitImage) +VK_DEVICE_PFN(vkCmdClearAttachments) +VK_DEVICE_PFN(vkCmdClearColorImage) +VK_DEVICE_PFN(vkCmdClearDepthStencilImage) +VK_DEVICE_PFN(vkCmdCopyBuffer) +VK_DEVICE_PFN(vkCmdCopyBufferToImage) +VK_DEVICE_PFN(vkCmdCopyImage) +VK_DEVICE_PFN(vkCmdCopyImageToBuffer) +VK_DEVICE_PFN(vkCmdCopyQueryPoolResults) +VK_DEVICE_PFN(vkCmdDispatch) +VK_DEVICE_PFN(vkCmdDispatchIndirect) +VK_DEVICE_PFN(vkCmdDraw) +VK_DEVICE_PFN(vkCmdDrawIndexed) +VK_DEVICE_PFN(vkCmdDrawIndexedIndirect) +VK_DEVICE_PFN(vkCmdDrawIndirect) +VK_DEVICE_PFN(vkCmdEndQuery) +VK_DEVICE_PFN(vkCmdEndRenderPass) +VK_DEVICE_PFN(vkCmdExecuteCommands) +VK_DEVICE_PFN(vkCmdFillBuffer) +VK_DEVICE_PFN(vkCmdNextSubpass) +VK_DEVICE_PFN(vkCmdPipelineBarrier) +VK_DEVICE_PFN(vkCmdPushConstants) +VK_DEVICE_PFN(vkCmdResetEvent) +VK_DEVICE_PFN(vkCmdResetQueryPool) +VK_DEVICE_PFN(vkCmdResolveImage) +VK_DEVICE_PFN(vkCmdSetBlendConstants) +VK_DEVICE_PFN(vkCmdSetDepthBias) +VK_DEVICE_PFN(vkCmdSetDepthBounds) +VK_DEVICE_PFN(vkCmdSetEvent) +VK_DEVICE_PFN(vkCmdSetLineWidth) +VK_DEVICE_PFN(vkCmdSetScissor) +VK_DEVICE_PFN(vkCmdSetStencilCompareMask) +VK_DEVICE_PFN(vkCmdSetStencilReference) +VK_DEVICE_PFN(vkCmdSetStencilWriteMask) +VK_DEVICE_PFN(vkCmdSetViewport) +VK_DEVICE_PFN(vkCmdUpdateBuffer) +VK_DEVICE_PFN(vkCmdWaitEvents) +VK_DEVICE_PFN(vkCmdWriteTimestamp) +VK_DEVICE_PFN(vkCreateBuffer) +VK_DEVICE_PFN(vkCreateBufferView) +VK_DEVICE_PFN(vkCreateCommandPool) +VK_DEVICE_PFN(vkCreateComputePipelines) +VK_DEVICE_PFN(vkCreateDescriptorPool) +VK_DEVICE_PFN(vkCreateDescriptorSetLayout) +VK_DEVICE_PFN(vkCreateEvent) +VK_DEVICE_PFN(vkCreateFence) +VK_DEVICE_PFN(vkCreateFramebuffer) +VK_DEVICE_PFN(vkCreateGraphicsPipelines) +VK_DEVICE_PFN(vkCreateImage) +VK_DEVICE_PFN(vkCreateImageView) +VK_DEVICE_PFN(vkCreatePipelineCache) +VK_DEVICE_PFN(vkCreatePipelineLayout) +VK_DEVICE_PFN(vkCreateQueryPool) +VK_DEVICE_PFN(vkCreateRenderPass) +VK_DEVICE_PFN(vkCreateSampler) +VK_DEVICE_PFN(vkCreateSemaphore) +VK_DEVICE_PFN(vkCreateShaderModule) +VK_DEVICE_PFN(vkDestroyBuffer) +VK_DEVICE_PFN(vkDestroyBufferView) +VK_DEVICE_PFN(vkDestroyCommandPool) +VK_DEVICE_PFN(vkDestroyDescriptorPool) +VK_DEVICE_PFN(vkDestroyDescriptorSetLayout) +VK_DEVICE_PFN(vkDestroyDevice) +VK_DEVICE_PFN(vkDestroyEvent) +VK_DEVICE_PFN(vkDestroyFence) +VK_DEVICE_PFN(vkDestroyFramebuffer) +VK_DEVICE_PFN(vkDestroyImage) +VK_DEVICE_PFN(vkDestroyImageView) +VK_DEVICE_PFN(vkDestroyPipeline) +VK_DEVICE_PFN(vkDestroyPipelineCache) +VK_DEVICE_PFN(vkDestroyPipelineLayout) +VK_DEVICE_PFN(vkDestroyQueryPool) +VK_DEVICE_PFN(vkDestroyRenderPass) +VK_DEVICE_PFN(vkDestroySampler) +VK_DEVICE_PFN(vkDestroySemaphore) +VK_DEVICE_PFN(vkDestroyShaderModule) +VK_DEVICE_PFN(vkDeviceWaitIdle) +VK_DEVICE_PFN(vkEndCommandBuffer) +VK_DEVICE_PFN(vkFlushMappedMemoryRanges) +VK_DEVICE_PFN(vkFreeCommandBuffers) +VK_DEVICE_PFN(vkFreeDescriptorSets) +VK_DEVICE_PFN(vkFreeMemory) +VK_DEVICE_PFN(vkGetBufferMemoryRequirements) +VK_DEVICE_PFN(vkGetDeviceMemoryCommitment) +VK_DEVICE_PFN(vkGetDeviceQueue) +VK_DEVICE_PFN(vkGetEventStatus) +VK_DEVICE_PFN(vkGetFenceStatus) +VK_DEVICE_PFN(vkGetImageMemoryRequirements) +VK_DEVICE_PFN(vkGetImageSparseMemoryRequirements) +VK_DEVICE_PFN(vkGetImageSubresourceLayout) +VK_DEVICE_PFN(vkGetPipelineCacheData) +VK_DEVICE_PFN(vkGetQueryPoolResults) +VK_DEVICE_PFN(vkGetRenderAreaGranularity) +VK_DEVICE_PFN(vkInvalidateMappedMemoryRanges) +VK_DEVICE_PFN(vkMapMemory) +VK_DEVICE_PFN(vkMergePipelineCaches) +VK_DEVICE_PFN(vkQueueBindSparse) +VK_DEVICE_PFN(vkQueueSubmit) +VK_DEVICE_PFN(vkQueueWaitIdle) +VK_DEVICE_PFN(vkResetCommandBuffer) +VK_DEVICE_PFN(vkResetCommandPool) +VK_DEVICE_PFN(vkResetDescriptorPool) +VK_DEVICE_PFN(vkResetEvent) +VK_DEVICE_PFN(vkResetFences) +VK_DEVICE_PFN(vkSetEvent) +VK_DEVICE_PFN(vkUnmapMemory) +VK_DEVICE_PFN(vkUpdateDescriptorSets) +VK_DEVICE_PFN(vkWaitForFences) + +#undef VK_INSTANCE_PFN +#undef VK_DEVICE_PFN