diff options
author | Jordan Halase <jordan@halase.me> | 2019-10-30 22:13:33 -0500 |
---|---|---|
committer | Jordan Halase <jordan@halase.me> | 2019-10-30 22:13:33 -0500 |
commit | ad0f0214fd4990a2460dfc84b8ceaf3fa7dc8946 (patch) | |
tree | 05ed136973fa04c08a9be5881b4ba71cadf799ee | |
parent | b4343ba193c7aad210d8b47cf339451f2686881a (diff) |
Open logical device
-rw-r--r-- | main.c | 162 |
1 files changed, 137 insertions, 25 deletions
@@ -67,6 +67,7 @@ PERFORMANCE OF THIS SOFTWARE. */ #define ALLOC_VK NULL +/** Instance-level Vulkan functions and handle */ struct VulkanAPI { void *handle; PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; @@ -81,11 +82,20 @@ struct VulkanAPI { PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; + PFN_vkCreateDevice vkCreateDevice; + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +}; + +/** Device-level Vulkan functions */ +struct VulkanDev { + PFN_vkDestroyDevice vkDestroyDevice; + PFN_vkDeviceWaitIdle vkDeviceWaitIdle; }; /** Vulkan application that uses Pugl for windows and events */ struct RenderVulkan { struct VulkanAPI *api; + struct VulkanDev *dev; PuglWorld *world; char *errMsg; VkInstance instance; @@ -367,27 +377,7 @@ static void rvkDestroyInstance(struct RenderVulkan *vk) vk->instance = VK_NULL_HANDLE; } -/** This must work no matter the current state of `vk` */ -void rvkDestroy(struct RenderVulkan *vk) -{ - if (vk) { - // TODO - // /* `vk->device` implies `vk->dev` and all device functions loaded */ - // if (vk->device) vk->dev->vkDeviceWaitIdle(vk->device); - if (vk->surface) vk->api->vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); - if (vk->debugCallback) { - /* `vk->debugCallback` implies `vk->api` and all instance functions loaded */ - vk->api->vkDestroyDebugReportCallbackEXT(vk->instance, vk->debugCallback, ALLOC_VK); - } - if (vk->instance) rvkDestroyInstance(vk); - if (vk->api) { - if (vk->api->handle) unloadVulkanLibrary(vk->api->handle); - free(vk->api); - } - if (vk->errMsg) free(vk->errMsg); - free(vk); - } -} +void rvkDestroy(struct RenderVulkan *vk); /** Create a self-contained Vulkan instance and set up a debug reporter * @@ -452,7 +442,7 @@ int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut) return -1; } - static const char *const strErrLd = "Error loading function %s"; + static const char *const strErrLd = "Error loading instance function %s"; static const char *const strDestroyInstance = "vkDestroyInstance"; uintptr_t *const ulDestroyInstance = (uintptr_t*)&vk->api->vkDestroyInstance; @@ -536,9 +526,27 @@ int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut) rvkSetErrMsg(vk, strErrLd, strEnumerateDeviceExtensionProperties); return -1; } + + static const char *const _vkCreateDevice = "vkCreateDevice"; + uintptr_t *__vkCreateDevice = (uintptr_t*)&vk->api->vkCreateDevice; + *__vkCreateDevice = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, _vkCreateDevice); + if (!vk->api->vkCreateDevice) { + rvkSetErrMsg(vk, strErrLd, _vkCreateDevice); + return -1; + } + + static const char *const strGetDeviceProcAddr = "vkGetDeviceProcAddr"; + uintptr_t *ulGetDeviceProcAddr = (uintptr_t*)&vk->api->vkGetDeviceProcAddr; + *ulGetDeviceProcAddr = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetDeviceProcAddr); + if (!vk->api->vkGetDeviceProcAddr) { + rvkSetErrMsg(vk, strErrLd, strGetDeviceProcAddr); + return -1; + } + /* End loading function pointers */ if (vk->api->vkCreateDebugReportCallbackEXT) { + printf("Creating debug reporter\n"); VkDebugReportCallbackCreateInfoEXT debugInfo = { 0 }; debugInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; debugInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; @@ -725,6 +733,106 @@ done: return ret; } +static int rvkLoadDeviceFunctions(struct RenderVulkan *vk, VkDevice device) +{ + const char *const strErrLd = "Error loading device function %s"; + + static const char *const _vkDestroyDevice = "vkDestroyDevice"; + uintptr_t *__vkDestroyDevice = (uintptr_t*)&vk->dev->vkDestroyDevice; + *__vkDestroyDevice = (uintptr_t)vk->api->vkGetDeviceProcAddr(device, _vkDestroyDevice); + if (!vk->dev->vkDestroyDevice) { + rvkSetErrMsg(vk, strErrLd, _vkDestroyDevice); + return -1; + } + + static const char *const _vkDeviceWaitIdle = "vkDeviceWaitIdle"; + uintptr_t *__vkDeviceWaitIdle = (uintptr_t*)&vk->dev->vkDeviceWaitIdle; + *__vkDeviceWaitIdle = (uintptr_t)vk->api->vkGetDeviceProcAddr(device, _vkDeviceWaitIdle); + if (!vk->dev->vkDeviceWaitIdle) { + rvkSetErrMsg(vk, strErrLd, _vkDeviceWaitIdle); + return -1; + } + + return 0; +} + +int rvkOpenDevice(struct RenderVulkan *vk) +{ + if (vk->device) { + rvkSetErrMsg(vk, "Renderer already has an opened device"); + return -1; + } + const float graphicsQueuePriority = 1.0f; + const char *const swapchainName = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + VkDeviceQueueCreateInfo queueCreateInfo = { 0 }; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = vk->graphicsIndex; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &graphicsQueuePriority; + + VkDeviceCreateInfo createInfo = { 0 }; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = 1; + createInfo.pQueueCreateInfos = &queueCreateInfo; + /* `enabledLayerCount` and `ppEnabledLayerNames` are ignored by modern Vulkan implementations. + * TODO: But maybe it is a good idea to support the older implementations. + */ + createInfo.enabledExtensionCount = 1; + createInfo.ppEnabledExtensionNames = &swapchainName; + /* This application uses no device features. */ + createInfo.pEnabledFeatures = NULL; + + VkDevice device; + VkResult result; + if ((result = vk->api->vkCreateDevice(vk->physicalDevice, &createInfo, ALLOC_VK, &device))) { + rvkSetErrMsg(vk, "Could not open device `%s`: %d\n", + vk->deviceProperties.deviceName, result); + return -1; + } + vk->dev = calloc(1, sizeof(*vk->dev)); + vk->device = device; + if (rvkLoadDeviceFunctions(vk, device)) { + return -1; + } + return 0; +} + +static void rvkCloseDevice(struct RenderVulkan *vk) +{ + if (vk->dev->vkDestroyDevice) { + vk->dev->vkDestroyDevice(vk->device, ALLOC_VK); + } else { + fprintf(stderr, "Fatal: Unable to destroy logical device (missing function pointer)\n"); + } + free(vk->dev); + vk->dev = NULL; + vk->device = VK_NULL_HANDLE; +} + +/** This must work no matter the current state of `vk` */ +void rvkDestroy(struct RenderVulkan *vk) +{ + if (vk) { + /* `vk->device` implies `vk->dev` but device functions MAY not be loaded */ + if (vk->device) { + if (vk->dev->vkDeviceWaitIdle) vk->dev->vkDeviceWaitIdle(vk->device); + rvkCloseDevice(vk); + } + if (vk->surface) vk->api->vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); + if (vk->debugCallback) { + /* `vk->debugCallback` implies `vk->api` and all instance functions loaded */ + vk->api->vkDestroyDebugReportCallbackEXT(vk->instance, vk->debugCallback, ALLOC_VK); + } + if (vk->instance) rvkDestroyInstance(vk); + if (vk->api) { + if (vk->api->handle) unloadVulkanLibrary(vk->api->handle); + free(vk->api); + } + if (vk->errMsg) free(vk->errMsg); + free(vk); + } +} + /* Normally, we would NOT exit the entire process on errors when running as * part of a larger process, but since we own this process, there isn't anything * else to do. As a plugin, we would destroy the window and all memory @@ -766,7 +874,7 @@ int main() #endif PuglWorld *world = puglNewWorld(); - /** Vulkan application that uses Pugl for windows and events */ + /* Vulkan application that uses Pugl for windows and events */ struct RenderVulkan *vk = NULL; CHECK_RVK(vk, rvkCreate(world, &vk)); @@ -785,6 +893,9 @@ int main() CHECK_RVK(vk, rvkCreateSurface(vk, view)); CHECK_RVK(vk, rvkSelectPhysicalDevice(vk)); + CHECK_RVK(vk, rvkOpenDevice(vk)); + + printf("Opened Vulkan Device Successfully\n"); puglShowWindow(view); while (running) { @@ -794,7 +905,7 @@ int main() puglFreeView(view); puglFreeWorld(world); - /* Vulkan library MUST be unloaded AFTER call to XCloseDisplay() or it will segfault */ + /* Vulkan library MUST be unloaded AFTER call to XCloseDisplay() or it will segfault (?) */ rvkDestroy(vk); printf("Exiting gracefully\n"); return 0; @@ -815,4 +926,5 @@ int WINAPI WinMain( (void)nCmdShow; return main(); } -#endif +#endif /* _WIN32 */ +#endif /* 0 */ |