From 4293fa94b6a4f1b97c292390b89827fcaf861d9f Mon Sep 17 00:00:00 2001 From: Jordan Halase Date: Mon, 28 Oct 2019 21:46:49 -0500 Subject: Add Pugl and overhaul --- main.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 139 insertions(+), 37 deletions(-) diff --git a/main.c b/main.c index 0d479b8..30d2933 100644 --- a/main.c +++ b/main.c @@ -43,8 +43,12 @@ PERFORMANCE OF THIS SOFTWARE. #else #include #include +#include "pugl/detail/x11.h" #endif +#include "pugl/pugl.h" +#include "pugl/pugl_stub_backend.h" + #define STB_SPRINTF_IMPLEMENTATION #include "stb_sprintf.h" @@ -68,6 +72,7 @@ struct VulkanAPI { PFN_vkDestroyInstance vkDestroyInstance; PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; + PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; @@ -86,18 +91,18 @@ struct RenderVulkan { VkDevice device; }; -#define ERRMSG_LEN 4096 +#define RVK_ERRMSG_LEN 4096 -void setErrMsg(struct RenderVulkan *vk, const char *fmt, ...) +void rvkSetErrMsg(struct RenderVulkan *vk, const char *fmt, ...) { - vk->errMsg = realloc(vk->errMsg, ERRMSG_LEN); + vk->errMsg = realloc(vk->errMsg, RVK_ERRMSG_LEN); va_list args; va_start(args, fmt); - stbsp_vsnprintf(vk->errMsg, ERRMSG_LEN, fmt, args); + stbsp_vsnprintf(vk->errMsg, RVK_ERRMSG_LEN, fmt, args); va_end(args); } -void clearErrMsg(struct RenderVulkan *vk) +void rvkClearErrMsg(struct RenderVulkan *vk) { if (vk->errMsg) { free(vk->errMsg); @@ -105,7 +110,7 @@ void clearErrMsg(struct RenderVulkan *vk) } } -const char *getErrMsg(struct RenderVulkan *vk) +const char *rvkGetErrMsg(struct RenderVulkan *vk) { return vk->errMsg; } @@ -154,6 +159,23 @@ void getRequiredInstanceExtensions(void *windowCtx, *nRequired = num; } } + +VkResult createVulkanSurface(PuglView *view, + VkInstance instance, + PFN_vkGetInstanceProcAddr getInstanceProcAddrFunc, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) +{ + PuglWorld *world = ((struct PuglViewImpl*)view)->world; + VkWin32SurfaceCreateInfoKHR createInfo = { 0 }; + createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + createInfo.hinstance = GetModuleHandle(0); // FIXME + createInfo.hwnd = puglGetNativeWindow(view); + PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; + uintptr_t *const ulCreateWin32SurfaceKHR = (uintptr_t*)&vkCreateWin32SurfaceKHR; + *ulCreateWin32SurfaceKHR = (uintptr_t)getInstanceProcAddrFunc(instance, "vkCreateWin32SurfaceKHR"); + return vkCreateWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface); +} #else #define VULKAN_SONAME_LATEST "libvulkan.so.1" #include @@ -177,7 +199,8 @@ int appDlclose(void *handle) return dlclose(handle); } -/* TODO: Linux actually has three possible surfaces: Xlib, XCB, and Wayland. +/* XXX: puglGetRequiredInstanceExtensions() + * TODO: Linux actually has three possible surfaces: Xlib, XCB, and Wayland. * This should be figured out at runtime (without using #ifdefs). * In which case, `windowCtx` will be used to determine which to use. * As of now, Pugl (and LV2!) only supports Xlib. @@ -200,6 +223,26 @@ void getRequiredInstanceExtensions(void *windowCtx, *nRequired = num; } } + +/* XXX: puglCreateVulkanSurface() + * No need to wrap VkFreeSurfaceKHR() + */ +VkResult createVulkanSurface(PuglView *view, + VkInstance instance, + PFN_vkGetInstanceProcAddr getInstanceProcAddrFunc, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) +{ + PuglWorld *world = ((struct PuglViewImpl*)view)->world; + VkXlibSurfaceCreateInfoKHR createInfo = { 0 }; + createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + createInfo.dpy = ((struct PuglWorldImpl*)world)->impl->display; + createInfo.window = puglGetNativeWindow(view); + PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; + uintptr_t *const ulCreateXlibSurfaceKHR = (uintptr_t*)&vkCreateXlibSurfaceKHR; + *ulCreateXlibSurfaceKHR = (uintptr_t)getInstanceProcAddrFunc(instance, "vkCreateXlibSurfaceKHR"); + return vkCreateXlibSurfaceKHR(instance, &createInfo, pAllocator, pSurface); +} #endif void *loadVulkanLibrary(const char *prefix) @@ -239,7 +282,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( return VK_FALSE; } -VkResult createInstance(struct RenderVulkan *vk, +static VkResult createInstance(struct RenderVulkan *vk, const uint32_t nLayers, const char *const *const layers, const uint32_t nAdditional, const char *const *const additionalExtensions) { @@ -281,23 +324,24 @@ VkResult createInstance(struct RenderVulkan *vk, VkResult result = VK_SUCCESS; if ((result = vk->api->vkCreateInstance(&createInfo, ALLOC_VK, &vk->instance))) { - setErrMsg(vk, "Could not create Vulkan Instance: %d\n", result); + rvkSetErrMsg(vk, "Could not create Vulkan Instance: %d\n", result); } free(extensions); return result; } /** Must not be called until all derivative objects are destroyed first */ -void destroyInstance(struct RenderVulkan *vk) +static void destroyInstance(struct RenderVulkan *vk) { vk->api->vkDestroyInstance(vk->instance, ALLOC_VK); vk->instance = VK_NULL_HANDLE; } /** This must work no matter the current state of `vk` */ -void renderVulkanDestroy(struct RenderVulkan *vk) +void rvkDestroy(struct RenderVulkan *vk) { if (vk) { + if (vk->surface) vk->api->vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); if (vk->debugCallback) { /* `vk->debugCallback` implies `vk->api` and instance functions loaded */ vk->api->vkDestroyDebugReportCallbackEXT(vk->instance, vk->debugCallback, ALLOC_VK); @@ -315,10 +359,10 @@ void renderVulkanDestroy(struct RenderVulkan *vk) /** Create a self-contained Vulkan instance and set up a debug reporter * * If errors occurred, the struct will be returned in an unusable state, - * and MUST be checked via `getErrMsg`. It MUST then be destroyed via - * `renderVulkanDestroy`. + * and MUST be checked via `rvkGetErrMsg`. It MUST then be destroyed via + * `rvkDestroy`. * */ -struct RenderVulkan *renderVulkanCreate() +struct RenderVulkan *rvkCreate() { static const char *const instanceLayers[] = { "VK_LAYER_LUNARG_standard_validation" @@ -334,20 +378,20 @@ struct RenderVulkan *renderVulkanCreate() vk->api->handle = loadVulkanLibrary(NULL); if (!vk->api->handle) { - setErrMsg(vk, "Error loading Vulkan shared library:\n%s\n", appDlerror()); + rvkSetErrMsg(vk, "Error loading Vulkan shared library:\n%s\n", appDlerror()); return vk; } loadVulkanGetInstanceProcAddrFunc(vk->api->handle, &vk->api->vkGetInstanceProcAddr); if (!vk->api->vkGetInstanceProcAddr) { - setErrMsg(vk, "Error loading `vkGetInstanceProcAddr`:\n%s", appDlerror()); + rvkSetErrMsg(vk, "Error loading `vkGetInstanceProcAddr`:\n%s", appDlerror()); return vk; } uintptr_t *const ulCreateInstance = (uintptr_t*)&vk->api->vkCreateInstance; *ulCreateInstance = (uintptr_t)vk->api->vkGetInstanceProcAddr(NULL, "vkCreateInstance"); if (!vk->api->vkCreateInstance) { - setErrMsg(vk, "Error loading `vkCreateInstance`"); + rvkSetErrMsg(vk, "Error loading `vkCreateInstance`"); return vk; } @@ -364,7 +408,7 @@ struct RenderVulkan *renderVulkanCreate() uintptr_t *const ulDestroyInstance = (uintptr_t*)&vk->api->vkDestroyInstance; *ulDestroyInstance = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strDestroyInstance); if (!vk->api->vkDestroyInstance) { - setErrMsg(vk, strErrLd, strDestroyInstance); + rvkSetErrMsg(vk, strErrLd, strDestroyInstance); return vk; } @@ -377,7 +421,15 @@ struct RenderVulkan *renderVulkanCreate() /* But not if we are unable to destroy a created debug reporter */ if (vk->api->vkCreateDebugReportCallbackEXT && !vk->api->vkDestroyDebugReportCallbackEXT) { - setErrMsg(vk, "No debug reporter destroy function loaded for corresponding create function\n"); + rvkSetErrMsg(vk, "No debug reporter destroy function loaded for corresponding create function\n"); + return vk; + } + + static const char *const strDestroySurfaceKHR = "vkDestroySurfaceKHR"; + uintptr_t *ulDestroySurfaceKHR = (uintptr_t*)&vk->api->vkDestroySurfaceKHR; + *ulDestroySurfaceKHR = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strDestroySurfaceKHR); + if (!vk->api->vkDestroySurfaceKHR) { + rvkSetErrMsg(vk, strErrLd, strDestroySurfaceKHR); return vk; } @@ -385,7 +437,7 @@ struct RenderVulkan *renderVulkanCreate() uintptr_t *ulEnumeratePhysicalDevices = (uintptr_t*)&vk->api->vkEnumeratePhysicalDevices; *ulEnumeratePhysicalDevices = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strEnumeratePhysicalDevices); if (!vk->api->vkEnumeratePhysicalDevices) { - setErrMsg(vk, strErrLd, strEnumeratePhysicalDevices); + rvkSetErrMsg(vk, strErrLd, strEnumeratePhysicalDevices); return vk; } @@ -393,7 +445,7 @@ struct RenderVulkan *renderVulkanCreate() uintptr_t *ulGetPhysicalDeviceProperties = (uintptr_t*)&vk->api->vkGetPhysicalDeviceProperties; *ulGetPhysicalDeviceProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceProperties); if (!vk->api->vkGetPhysicalDeviceProperties) { - setErrMsg(vk, strErrLd, strGetPhysicalDeviceProperties); + rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceProperties); return vk; } @@ -401,7 +453,7 @@ struct RenderVulkan *renderVulkanCreate() uintptr_t *ulGetPhysicalDeviceQueueFamilyProperties = (uintptr_t*)&vk->api->vkGetPhysicalDeviceQueueFamilyProperties; *ulGetPhysicalDeviceQueueFamilyProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceQueueFamilyProperties); if (!vk->api->vkGetPhysicalDeviceQueueFamilyProperties) { - setErrMsg(vk, strErrLd, strGetPhysicalDeviceQueueFamilyProperties); + rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceQueueFamilyProperties); return vk; } @@ -409,7 +461,7 @@ struct RenderVulkan *renderVulkanCreate() uintptr_t *ulGetPhysicalDeviceSurfaceSupportKHR = (uintptr_t*)&vk->api->vkGetPhysicalDeviceSurfaceSupportKHR; *ulGetPhysicalDeviceSurfaceSupportKHR = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceSurfaceSupportKHR); if (!vk->api->vkGetPhysicalDeviceSurfaceSupportKHR) { - setErrMsg(vk, strErrLd, strGetPhysicalDeviceSurfaceSupportKHR); + rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceSurfaceSupportKHR); return vk; } @@ -417,7 +469,7 @@ struct RenderVulkan *renderVulkanCreate() uintptr_t *ulGetPhysicalDeviceMemoryProperties = (uintptr_t*)&vk->api->vkGetPhysicalDeviceMemoryProperties; *ulGetPhysicalDeviceMemoryProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceMemoryProperties); if (!vk->api->vkGetPhysicalDeviceMemoryProperties) { - setErrMsg(vk, strErrLd, strGetPhysicalDeviceMemoryProperties); + rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceMemoryProperties); return vk; } @@ -425,7 +477,7 @@ struct RenderVulkan *renderVulkanCreate() uintptr_t *ulEnumerateDeviceExtensionProperties = (uintptr_t*)&vk->api->vkEnumerateDeviceExtensionProperties; *ulEnumerateDeviceExtensionProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strEnumerateDeviceExtensionProperties); if (!vk->api->vkEnumerateDeviceExtensionProperties) { - setErrMsg(vk, strErrLd, strEnumerateDeviceExtensionProperties); + rvkSetErrMsg(vk, strErrLd, strEnumerateDeviceExtensionProperties); return vk; } @@ -436,7 +488,7 @@ struct RenderVulkan *renderVulkanCreate() debugInfo.pfnCallback = debugCallback; if ((result = vk->api->vkCreateDebugReportCallbackEXT(vk->instance, &debugInfo, ALLOC_VK, &vk->debugCallback))) { - setErrMsg(vk, "Could not create debug reporter: %d", result); + rvkSetErrMsg(vk, "Could not create debug reporter: %d", result); return vk; } } @@ -444,6 +496,14 @@ struct RenderVulkan *renderVulkanCreate() return vk; } +static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view) +{ + VkResult result; + if ((result = createVulkanSurface(view, vk->instance, vk->api->vkGetInstanceProcAddr, ALLOC_VK, &vk->surface))) { + rvkSetErrMsg(vk, "Could not create window surface: %d\n", result); + } +} + int isDeviceSuitable(struct RenderVulkan *vk, VkPhysicalDevice pd) { uint32_t nQueueFamilies; @@ -472,10 +532,10 @@ int isDeviceSuitable(struct RenderVulkan *vk, VkPhysicalDevice pd) return 1; } -void selectPhysicalDevice(struct RenderVulkan *vk) +void rvkSelectPhysicalDevice(struct RenderVulkan *vk) { if (!vk->surface) { - setErrMsg(vk, "Cannot select a physical device without a surface"); + rvkSetErrMsg(vk, "Cannot select a physical device without a surface"); return; } static const char *const strErrEnum = "Could not enumerate physical devices: %s"; @@ -484,20 +544,20 @@ void selectPhysicalDevice(struct RenderVulkan *vk) VkResult result; if ((result = vk->api->vkEnumeratePhysicalDevices(vk->instance, &nDevices, NULL))) { if (result != VK_INCOMPLETE) { - setErrMsg(vk, strErrEnum, result); + rvkSetErrMsg(vk, strErrEnum, result); return; } else { fprintf(stderr, "%s\n", strWarnEnum); } } if (!nDevices) { - setErrMsg(vk, "No physical devices found"); + rvkSetErrMsg(vk, "No physical devices found"); return; } VkPhysicalDevice *devices = malloc(nDevices * sizeof(*devices)); if ((result = vk->api->vkEnumeratePhysicalDevices(vk->instance, &nDevices, devices))) { if (result != VK_INCOMPLETE) { - setErrMsg(vk, strErrEnum, result); + rvkSetErrMsg(vk, strErrEnum, result); goto done; } else { fprintf(stderr, "%s\n", strWarnEnum); @@ -521,7 +581,7 @@ void selectPhysicalDevice(struct RenderVulkan *vk) printf("Device `%s` not suitable\n", deviceProperties.deviceName); } if (i >= nDevices) { - setErrMsg(vk, "No suitable devices found"); + rvkSetErrMsg(vk, "No suitable devices found"); } done: free(devices); @@ -530,25 +590,67 @@ done: void rvkCheckFatal(struct RenderVulkan *vk) { const char *errMsg = NULL; - if ((errMsg = getErrMsg(vk))) { + if ((errMsg = rvkGetErrMsg(vk))) { fprintf(stderr, "%s\n", errMsg); - renderVulkanDestroy(vk); + rvkDestroy(vk); exit(1); } } +int running = 1; + +PuglStatus onEvent(PuglView *view, const PuglEvent *e) +{ + switch (e->type) { + case PUGL_CLOSE: + running = 0; + break; + default: + break; + } + return PUGL_SUCCESS; +} + int main() { +#if defined(__linux__) + XInitThreads(); +#endif const char *errMsg = NULL; - struct RenderVulkan *vk = renderVulkanCreate(); + struct RenderVulkan *vk = rvkCreate(); rvkCheckFatal(vk); printf("Created Vulkan Instance Successfully\n"); - selectPhysicalDevice(vk); + PuglWorld *world = puglNewWorld(); + PuglView *view = puglNewView(world); + const PuglRect frame = { 0, 0, 800, 600 }; + puglSetBackend(view, puglStubBackend()); + + PuglStatus status; + if ((status = puglCreateWindow(view, "Pugl Vulkan Test"))) { + fprintf(stderr, "Could not create window: %d\n", status); + rvkDestroy(vk); + puglFreeWorld(world); + exit(1); + } + puglSetEventFunc(view, onEvent); + + rvkCreateSurface(vk, view); rvkCheckFatal(vk); - renderVulkanDestroy(vk); + rvkSelectPhysicalDevice(vk); + rvkCheckFatal(vk); + + puglShowWindow(view); + while (running) { + puglPollEvents(world, -1); + puglDispatchEvents(world); + } + + puglFreeView(view); + puglFreeWorld(world); + rvkDestroy(vk); return 0; } -- cgit v1.2.1