summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c162
1 files changed, 137 insertions, 25 deletions
diff --git a/main.c b/main.c
index b52b850..1b50108 100644
--- a/main.c
+++ b/main.c
@@ -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 */