summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c117
1 files changed, 65 insertions, 52 deletions
diff --git a/main.c b/main.c
index e0d2451..fd2d74d 100644
--- a/main.c
+++ b/main.c
@@ -312,7 +312,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
return VK_FALSE;
}
-static VkResult createInstance(struct RenderVulkan *vk,
+static VkResult rvkCreateInstance(struct RenderVulkan *vk,
const uint32_t nLayers, const char *const *const layers,
const uint32_t nAdditional, const char *const *const additionalExtensions)
{
@@ -361,7 +361,7 @@ static VkResult createInstance(struct RenderVulkan *vk,
}
/** Must not be called until all derivative objects are destroyed first */
-static void destroyInstance(struct RenderVulkan *vk)
+static void rvkDestroyInstance(struct RenderVulkan *vk)
{
vk->api->vkDestroyInstance(vk->instance, ALLOC_VK);
vk->instance = VK_NULL_HANDLE;
@@ -371,18 +371,21 @@ static void destroyInstance(struct RenderVulkan *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 instance functions loaded */
+ /* `vk->debugCallback` implies `vk->api` and all instance functions loaded */
vk->api->vkDestroyDebugReportCallbackEXT(vk->instance, vk->debugCallback, ALLOC_VK);
}
- if (vk->instance) destroyInstance(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);
- if (vk) free(vk);
+ free(vk);
}
}
@@ -405,7 +408,7 @@ void rvkDestroy(struct RenderVulkan *vk)
* and MUST be checked via `rvkGetErrMsg`. It MUST then be destroyed via
* `rvkDestroy`.
* */
-struct RenderVulkan *rvkCreate(PuglWorld *world)
+int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut)
{
static const char *const instanceLayers[] = {
"VK_LAYER_LUNARG_standard_validation"
@@ -419,7 +422,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
struct RenderVulkan *vk = calloc(1, sizeof(*vk));
if (!world) {
rvkSetErrMsg(vk, "No PuglWorld provided");
- return vk;
+ return -1;
}
vk->world = world;
vk->api = calloc(1, sizeof(*vk->api));
@@ -427,26 +430,26 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
vk->api->handle = loadVulkanLibrary(NULL);
if (!vk->api->handle) {
rvkSetErrMsg(vk, "Error loading Vulkan shared library:\n%s\n", appDlerror());
- return vk;
+ return -1;
}
loadVulkanGetInstanceProcAddrFunc(vk->api->handle, &vk->api->vkGetInstanceProcAddr);
if (!vk->api->vkGetInstanceProcAddr) {
rvkSetErrMsg(vk, "Error loading `vkGetInstanceProcAddr`:\n%s", appDlerror());
- return vk;
+ return -1;
}
uintptr_t *const ulCreateInstance = (uintptr_t*)&vk->api->vkCreateInstance;
*ulCreateInstance = (uintptr_t)vk->api->vkGetInstanceProcAddr(NULL, "vkCreateInstance");
if (!vk->api->vkCreateInstance) {
rvkSetErrMsg(vk, "Error loading `vkCreateInstance`");
- return vk;
+ return -1;
}
VkResult result;
- //if ((result = createInstance(vk, 0, NULL, 0, NULL))) {
- if ((result = createInstance(vk, nInstanceLayers, instanceLayers, nInstanceExtensions, instanceExtensions))) {
- return vk;
+ //if ((result = rvkCreateInstance(vk, 0, NULL, 0, NULL))) {
+ if ((result = rvkCreateInstance(vk, nInstanceLayers, instanceLayers, nInstanceExtensions, instanceExtensions))) {
+ return -1;
}
static const char *const strErrLd = "Error loading function %s";
@@ -456,7 +459,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
*ulDestroyInstance = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strDestroyInstance);
if (!vk->api->vkDestroyInstance) {
rvkSetErrMsg(vk, strErrLd, strDestroyInstance);
- return vk;
+ return -1;
}
/* It is okay if debug reporter functions are not resolved (for now) */
@@ -469,7 +472,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
/* But not if we are unable to destroy a created debug reporter */
if (vk->api->vkCreateDebugReportCallbackEXT && !vk->api->vkDestroyDebugReportCallbackEXT) {
rvkSetErrMsg(vk, "No debug reporter destroy function loaded for corresponding create function\n");
- return vk;
+ return -1;
}
/* Dynamically load instance-level Vulkan function pointers via `vkGetInstanceProcAddr`
@@ -483,7 +486,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
*ulDestroySurfaceKHR = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strDestroySurfaceKHR);
if (!vk->api->vkDestroySurfaceKHR) {
rvkSetErrMsg(vk, strErrLd, strDestroySurfaceKHR);
- return vk;
+ return -1;
}
static const char *const strEnumeratePhysicalDevices = "vkEnumeratePhysicalDevices";
@@ -491,7 +494,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
*ulEnumeratePhysicalDevices = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strEnumeratePhysicalDevices);
if (!vk->api->vkEnumeratePhysicalDevices) {
rvkSetErrMsg(vk, strErrLd, strEnumeratePhysicalDevices);
- return vk;
+ return -1;
}
static const char *const strGetPhysicalDeviceProperties = "vkGetPhysicalDeviceProperties";
@@ -499,7 +502,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
*ulGetPhysicalDeviceProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceProperties);
if (!vk->api->vkGetPhysicalDeviceProperties) {
rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceProperties);
- return vk;
+ return -1;
}
static const char *const strGetPhysicalDeviceQueueFamilyProperties = "vkGetPhysicalDeviceQueueFamilyProperties";
@@ -507,7 +510,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
*ulGetPhysicalDeviceQueueFamilyProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceQueueFamilyProperties);
if (!vk->api->vkGetPhysicalDeviceQueueFamilyProperties) {
rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceQueueFamilyProperties);
- return vk;
+ return -1;
}
static const char *const strGetPhysicalDeviceSurfaceSupportKHR = "vkGetPhysicalDeviceSurfaceSupportKHR";
@@ -515,7 +518,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
*ulGetPhysicalDeviceSurfaceSupportKHR = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceSurfaceSupportKHR);
if (!vk->api->vkGetPhysicalDeviceSurfaceSupportKHR) {
rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceSurfaceSupportKHR);
- return vk;
+ return -1;
}
static const char *const strGetPhysicalDeviceMemoryProperties = "vkGetPhysicalDeviceMemoryProperties";
@@ -523,7 +526,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
*ulGetPhysicalDeviceMemoryProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strGetPhysicalDeviceMemoryProperties);
if (!vk->api->vkGetPhysicalDeviceMemoryProperties) {
rvkSetErrMsg(vk, strErrLd, strGetPhysicalDeviceMemoryProperties);
- return vk;
+ return -1;
}
static const char *const strEnumerateDeviceExtensionProperties = "vkEnumerateDeviceExtensionProperties";
@@ -531,7 +534,7 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
*ulEnumerateDeviceExtensionProperties = (uintptr_t)vk->api->vkGetInstanceProcAddr(vk->instance, strEnumerateDeviceExtensionProperties);
if (!vk->api->vkEnumerateDeviceExtensionProperties) {
rvkSetErrMsg(vk, strErrLd, strEnumerateDeviceExtensionProperties);
- return vk;
+ return -1;
}
/* End loading function pointers */
@@ -543,19 +546,22 @@ struct RenderVulkan *rvkCreate(PuglWorld *world)
if ((result = vk->api->vkCreateDebugReportCallbackEXT(vk->instance,
&debugInfo, ALLOC_VK, &vk->debugCallback))) {
rvkSetErrMsg(vk, "Could not create debug reporter: %d", result);
- return vk;
+ return -1;
}
}
- return vk;
+ *vkOut = vk;
+ return 0;
}
-static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view)
+static int 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);
+ return -1;
}
+ return 0;
}
/** Checks if a particular physical device is suitable for this application.
@@ -606,7 +612,7 @@ static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view)
* Information for many devices is available online at
* https://vulkan.gpuinfo.org/
*/
-static int rvkIsDeviceSuitable(const struct RenderVulkan *const vk,
+static bool rvkIsDeviceSuitable(const struct RenderVulkan *const vk,
const VkPhysicalDevice physicalDevice,
uint32_t *const graphicsIndex)
{
@@ -629,26 +635,26 @@ static int rvkIsDeviceSuitable(const struct RenderVulkan *const vk,
if (g >= nQueueFamilies) {
/* We only support graphics and present on the same queue family. */
printf("No graphics+support queue families found on this device\n");
- return 0;
+ return false;
}
- VkBool32 canSwapchain = 0;
+ VkBool32 canSwapchain = VK_FALSE;
uint32_t nExtensions;
vk->api->vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &nExtensions, NULL);
VkExtensionProperties *availableExtensions = malloc(nExtensions * sizeof(*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;
+ canSwapchain = VK_TRUE;
break;
}
}
free(availableExtensions);
if (!canSwapchain) {
printf("Cannot use a swapchain on this device\n");
- return 0;
+ return false;
}
*graphicsIndex = g;
- return 1;
+ return true;
}
/** Selects a physical device
@@ -656,11 +662,12 @@ static int rvkIsDeviceSuitable(const struct RenderVulkan *const vk,
* This application will not attempt to find the "most powerful" device on the
* system, and will choose the first suitable device it finds.
*/
-void rvkSelectPhysicalDevice(struct RenderVulkan *vk)
+int rvkSelectPhysicalDevice(struct RenderVulkan *vk)
{
+ int ret = 0;
if (!vk->surface) {
rvkSetErrMsg(vk, "Cannot select a physical device without a surface");
- return;
+ return -1;
}
static const char *const strErrEnum = "Could not enumerate physical devices: %s";
static const char *const strWarnEnum = "Warn: Incomplete enumeration of physical devices";
@@ -669,20 +676,21 @@ void rvkSelectPhysicalDevice(struct RenderVulkan *vk)
if ((result = vk->api->vkEnumeratePhysicalDevices(vk->instance, &nDevices, NULL))) {
if (result != VK_INCOMPLETE) {
rvkSetErrMsg(vk, strErrEnum, result);
- return;
+ return -1;
} else {
fprintf(stderr, "%s\n", strWarnEnum);
}
}
if (!nDevices) {
rvkSetErrMsg(vk, "No physical devices found");
- return;
+ return -1;
}
VkPhysicalDevice *devices = malloc(nDevices * sizeof(*devices));
VkPhysicalDeviceProperties *deviceProperties = malloc(nDevices * sizeof(*deviceProperties));
if ((result = vk->api->vkEnumeratePhysicalDevices(vk->instance, &nDevices, devices))) {
if (result != VK_INCOMPLETE) {
rvkSetErrMsg(vk, strErrEnum, result);
+ ret = -1;
goto done;
} else {
fprintf(stderr, "%s\n", strWarnEnum);
@@ -709,22 +717,32 @@ void rvkSelectPhysicalDevice(struct RenderVulkan *vk)
}
if (i >= nDevices) {
rvkSetErrMsg(vk, "No suitable devices found");
+ ret = -1;
}
done:
free(deviceProperties);
free(devices);
+ return ret;
}
-void rvkCheckFatal(struct RenderVulkan *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
+ * associated with it, leaving the larger process intact.
+ */
+static void rvkFatal(struct RenderVulkan *vk)
{
- const char *errMsg = NULL;
- if ((errMsg = rvkGetErrMsg(vk))) {
- fprintf(stderr, "%s\n", errMsg);
- rvkDestroy(vk);
- exit(1);
+ fprintf(stderr, "%s\n", rvkGetErrMsg(vk));
+ rvkDestroy(vk);
+ if (vk->world) {
+ puglFreeWorld(vk->world);
}
+ printf("Aborting gracefully\n");
+ exit(1);
}
+#define CHECK_RVK(rvk, expr) do { if ((expr)) { rvkFatal(rvk); } } while (0)
+
int running = 1;
PuglStatus onEvent(PuglView *view, const PuglEvent *e)
@@ -747,11 +765,10 @@ int main()
XInitThreads();
#endif
PuglWorld *world = puglNewWorld();
- const char *errMsg = NULL;
/** Vulkan application that uses Pugl for windows and events */
- struct RenderVulkan *vk = rvkCreate(world);
- rvkCheckFatal(vk);
+ struct RenderVulkan *vk = NULL;
+ CHECK_RVK(vk, rvkCreate(world, &vk));
printf("Created Vulkan Instance Successfully\n");
@@ -762,17 +779,12 @@ int main()
PuglStatus status;
if ((status = puglCreateWindow(view, "Vulkan Application Using Pugl"))) {
fprintf(stderr, "Could not create window: %d\n", status);
- rvkDestroy(vk);
- puglFreeWorld(world);
- exit(1);
+ rvkFatal(vk);
}
puglSetEventFunc(view, onEvent);
- rvkCreateSurface(vk, view);
- rvkCheckFatal(vk);
-
- rvkSelectPhysicalDevice(vk);
- rvkCheckFatal(vk);
+ CHECK_RVK(vk, rvkCreateSurface(vk, view));
+ CHECK_RVK(vk, rvkSelectPhysicalDevice(vk));
puglShowWindow(view);
while (running) {
@@ -784,6 +796,7 @@ int main()
puglFreeWorld(world);
/* Vulkan library MUST be unloaded AFTER call to XCloseDisplay() or it will segfault */
rvkDestroy(vk);
+ printf("Exiting gracefully\n");
return 0;
}