From d73a1c763f36e1560efc2536f8219784a32a617d Mon Sep 17 00:00:00 2001 From: Jordan Halase Date: Wed, 30 Oct 2019 11:46:26 -0500 Subject: Overhaul --- main.c | 79 ++++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/main.c b/main.c index dde113a..fb81e89 100644 --- a/main.c +++ b/main.c @@ -128,9 +128,10 @@ void *appDlopen(const char *soname) char *appDlerror() { + // TODO: Print a more informative string. Error codes are annoying. DWORD errCode = GetLastError(); static APP_THREAD_LOCAL char errStr[64]; - stbsp_sprintf(errStr, "Dynamic Library Error: %d", errCode); + stbsp_snprintf(errStr, sizeof(errStr), "Dynamic Library Error: %d", errCode); return errStr; } @@ -145,22 +146,22 @@ int appDlclose(void *handle) return FreeLibrary(handle); } -void getRequiredInstanceExtensions(void *windowCtx, - unsigned *nRequired, - const char **const extensions) +void getRequiredInstanceExtensions(PuglWorld *world, + unsigned *pExtensionCount, + const char **const ppExtensionNames) { - (void)windowCtx; + (void)world; static const char *const required[] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME }; static const unsigned num = sizeof(required) / sizeof(required[0]); - if (extensions) { + if (ppExtensionNames) { for (int i = 0; i < num; ++i) { - extensions[i] = required[i]; + ppExtensionNames[i] = required[i]; } } else { - *nRequired = num; + *pExtensionCount = num; } } @@ -205,27 +206,38 @@ int appDlclose(void *handle) } /* XXX: puglGetRequiredInstanceExtensions() + * This will return the platform-specific names of the instance level + * extensions required to display images to the screen. + * Vulkan is off-screen by default and can be used without presenting + * at all, so off-screen applications will not need to call this + * function. In other words: + * + * "Get the names of the required instance extensions if you want to + * display your images to the screen." + * * 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. + * In which case, `world` will be used to determine which to use. + * As of now, Pugl (and LV2! suil, etc.) only supports Xlib, but the + * variable should be left in the function signature for forward + * compatibility. */ -void getRequiredInstanceExtensions(void *windowCtx, - unsigned *nRequired, - const char **const extensions) +void getRequiredInstanceExtensions(PuglWorld *world, + unsigned *pExtensionCount, + const char **const ppExtensionNames) { - (void)windowCtx; + (void)world; static const char *const required[] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME }; static const unsigned num = sizeof(required) / sizeof(required[0]); - if (extensions) { + if (ppExtensionNames) { for (int i = 0; i < num; ++i) { - extensions[i] = required[i]; + ppExtensionNames[i] = required[i]; } } else { - *nRequired = num; + *pExtensionCount = num; } } @@ -406,7 +418,6 @@ struct RenderVulkan *rvkCreate() return vk; } - /* TODO: This could perhaps be generated */ static const char *const strErrLd = "Error loading function %s"; static const char *const strDestroyInstance = "vkDestroyInstance"; @@ -417,7 +428,7 @@ struct RenderVulkan *rvkCreate() return vk; } - /* It is okay if debug reporter functions are not resolved */ + /* It is okay if debug reporter functions are not resolved (for now) */ uintptr_t *ulCreateDebugReportCallbackEXT = (uintptr_t*)&vk->api->vkCreateDebugReportCallbackEXT; *ulCreateDebugReportCallbackEXT = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, "vkCreateDebugReportCallbackEXT"); @@ -430,6 +441,12 @@ struct RenderVulkan *rvkCreate() return vk; } + /* Dynamically load instance-level Vulkan function pointers via `vkGetInstanceProcAddr` + * + * TODO: This could perhaps be generated by a script and put into a separate "loader" file + * + * Casts to `uintptr_t` as an intermediary to suppress warnings when compiling with `-Wpedantic` + */ static const char *const strDestroySurfaceKHR = "vkDestroySurfaceKHR"; uintptr_t *ulDestroySurfaceKHR = (uintptr_t*)&vk->api->vkDestroySurfaceKHR; *ulDestroySurfaceKHR = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strDestroySurfaceKHR); @@ -485,6 +502,7 @@ struct RenderVulkan *rvkCreate() rvkSetErrMsg(vk, strErrLd, strEnumerateDeviceExtensionProperties); return vk; } + /* End loading function pointers */ if (vk->api->vkCreateDebugReportCallbackEXT) { VkDebugReportCallbackCreateInfoEXT debugInfo = { 0 }; @@ -510,6 +528,8 @@ static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view) } /** Checks if a particular physical device is suitable for this application. + * + * This function is referentially transparent. * * Choosing a physical device is an *extremely* application-specific procedure. * @@ -544,8 +564,9 @@ static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view) * must retrieve queues per-thread. * * GOTCHA: Some devices may have multiple GRAPHICS queue families - * with only one of them able to present. Do not assume a device is - * unsuitable until ALL queue families have been checked. + * with only one of them able to present. Do not assume a + * device is unsuitable until ALL queue families have been + * checked. * * Because this application will load all resources before any rendering begins, * and the amount of resources are small enough to be loaded almost instantly, @@ -557,13 +578,13 @@ static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view) * https://vulkan.gpuinfo.org/ */ static int isDeviceSuitable(const struct RenderVulkan *const vk, - const VkPhysicalDevice pd, + const VkPhysicalDevice physicalDevice, uint32_t *const graphicsIndex) { uint32_t nQueueFamilies; - vk->api->vkGetPhysicalDeviceQueueFamilyProperties(pd, &nQueueFamilies, NULL); + vk->api->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &nQueueFamilies, NULL); VkQueueFamilyProperties *queueProperties = malloc(nQueueFamilies * sizeof(*queueProperties)); - vk->api->vkGetPhysicalDeviceQueueFamilyProperties(pd, &nQueueFamilies, queueProperties); + vk->api->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &nQueueFamilies, queueProperties); for (uint32_t i = 0; i < nQueueFamilies; ++i) { printf("Queue Family %d queueCount:\t%d\n", i, queueProperties[i].queueCount); } @@ -571,7 +592,7 @@ static int isDeviceSuitable(const struct RenderVulkan *const vk, for (g = 0; g < nQueueFamilies; ++g) { if (queueProperties[g].queueFlags & VK_QUEUE_GRAPHICS_BIT) { VkBool32 canSurface; - vk->api->vkGetPhysicalDeviceSurfaceSupportKHR(pd, g, vk->surface, &canSurface); + vk->api->vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, g, vk->surface, &canSurface); if (canSurface) break; } } @@ -583,9 +604,9 @@ static int isDeviceSuitable(const struct RenderVulkan *const vk, } VkBool32 canSwapchain = 0; uint32_t nExtensions; - vk->api->vkEnumerateDeviceExtensionProperties(pd, NULL, &nExtensions, NULL); + vk->api->vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &nExtensions, NULL); VkExtensionProperties *availableExtensions = malloc(nExtensions * sizeof(*availableExtensions)); - vk->api->vkEnumerateDeviceExtensionProperties(pd, NULL, &nExtensions, availableExtensions); + vk->api->vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &nExtensions, availableExtensions); for (uint32_t i = 0; i < nExtensions; ++i) { if (!strcmp(availableExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { canSwapchain = 1; @@ -641,10 +662,12 @@ void rvkSelectPhysicalDevice(struct RenderVulkan *vk) } for (i = 0; i < nDevices; ++i) { printf("Checking suitability for\t`%s`...\n", deviceProperties[i].deviceName); - if (isDeviceSuitable(vk, devices[i], &vk->graphicsIndex)) { + uint32_t graphicsIndex; + if (isDeviceSuitable(vk, devices[i], &graphicsIndex)) { printf("Using physical device:\t\t`%s`\n", deviceProperties[i].deviceName); vk->deviceProperties = deviceProperties[i]; vk->physicalDevice = devices[i]; + vk->graphicsIndex = graphicsIndex; printf("Graphics Index:\t\t\t%d\n", vk->graphicsIndex); goto done; } -- cgit v1.2.1