diff options
| -rw-r--r-- | main.c | 117 | 
1 files changed, 65 insertions, 52 deletions
| @@ -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;  } | 
