diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | CMakeLists.txt | 17 | ||||
| -rw-r--r-- | compiling.txt | 13 | ||||
| -rw-r--r-- | main.c | 101 | 
4 files changed, 107 insertions, 25 deletions
| @@ -2,3 +2,4 @@ a.out  a.exe  *.swp  *.o +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3192c6a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.2) +project(vkpugltest LANGUAGES C) + +set(pugldir "../../pugl") +set(PUGL_INCLUDE "${pugldir}") +set(PUGL_LIBDIR "${pugldir}/build") +set(PUGL_LIBS "-L${PUGL_LIBDIR} -Wl,-rpath,${PUGL_LIBDIR}") + +include_directories(../pugl) +add_executable(vkpugltest main.c) +#link_directories(/home/jordan/Documents/Hack/pugl/build) +target_link_libraries(vkpugltest ${PUGL_LIBS}) +if (UNIX) +	target_link_libraries(vkpugltest pugl_x11 X11 dl) +elseif (WIN32) +	target_link_libraries(vkpugltest pugl_win) +endif (UNIX) diff --git a/compiling.txt b/compiling.txt new file mode 100644 index 0000000..b270272 --- /dev/null +++ b/compiling.txt @@ -0,0 +1,13 @@ +Right now building is still being figured out. + +As of now, the Windows version is compiled using Visual Studio and the Linux +version is compiled using CMake. + +Currently, on Windows, the file `pugl_win.dll` may need to be moved into the +executable directory. + +To compile on Linux, simply create a build directory, call CMake, then make. + +1)	mkdir build && cd build +2)	cmake .. +3)	make @@ -84,11 +84,13 @@ struct VulkanAPI {  struct RenderVulkan {  	struct VulkanAPI *api;  	char *errMsg; -	VkInstance instance; -	VkDebugReportCallbackEXT debugCallback; -	VkSurfaceKHR surface; -	uint32_t graphicsIndex; -	VkDevice device; +	VkInstance			instance; +	VkDebugReportCallbackEXT	debugCallback; +	VkSurfaceKHR			surface; +	VkPhysicalDeviceProperties	deviceProperties; +	VkPhysicalDevice		physicalDevice; +	uint32_t			graphicsIndex; +	VkDevice			device;  };  #define RVK_ERRMSG_LEN	4096 @@ -179,6 +181,7 @@ VkResult createVulkanSurface(PuglView *view,  #else  #define VULKAN_SONAME_LATEST	"libvulkan.so.1"  #include <dlfcn.h> +// XXX: puglDlopen()  void *appDlopen(const char *soname)  {  	return dlopen(soname, RTLD_NOW); @@ -504,7 +507,56 @@ static void rvkCreateSurface(struct RenderVulkan *vk, PuglView *view)  	}  } -int isDeviceSuitable(struct RenderVulkan *vk, VkPhysicalDevice pd) +/** Checks if a particular physical device is suitable for this application. + * + * Choosing a physical device is an *extremely* application-specific procedure. + * + * All rendering in Vulkan is done off-screen by default. To get rendered + * results on-screen they must be "presented" to a surface. + * The Vulkan spec allows devices to have presentation done on a separate queue + * family than GRAPHICS, or no present support at all. However, every graphics + * card today that is capable of connecting to a display has at least one queue + * family capable of both GRAPHICS and present. + * + * This single-threaded application will use only one queue for all operations. + * More specifically, it will make use of GRAPHICS and TRANSFER operations on + * a single queue retrieved from a GRAPHICS queue family that supports present. + * + * In my experience, most cards follow this format: + * + * INTEGRATED: Typically have one queue family for all operations. + *             May retrieve only one queue from this single queue family. + * DEDICATED:  Older cards typically have one queue family for GRAPHICS and one + *             for TRANSFER. Newer cards typically have a separate queue family + *             for COMPUTE. Remember that all GRAPHICS queue families + *             implicitly allow both COMPUTE and TRANSFER operations on it as + *             well. Programmers making use of separate queue families may allow + *             devices to work more efficiently. + * + *             May typically retrieve up to a few queues from either queue + *             family. The maximum number of available queues is specific to + *             that device's queue families. Programmers making use of separate + *             queues for highly independent workloads may allow devices to work + *             more efficiently. Queues must be used from a single thread, so + *             programmers wanting to make use of multithreaded queue submission + *             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. + * + * Because this application will load all resources before any rendering begins, + * and the amount of resources are small enough to be loaded almost instantly, + * it will not make use of a separate TRANSFER queue family. This application + * will also not attempt to find the "most powerful" device on the system, and + * will choose the first suitable device it finds. + * + * Information for many devices is available online at + * https://vulkan.gpuinfo.org/ + */ +static int isDeviceSuitable(const struct RenderVulkan *const vk, +		const VkPhysicalDevice pd, +		uint32_t *const graphicsIndex)  {  	uint32_t nQueueFamilies;  	vk->api->vkGetPhysicalDeviceQueueFamilyProperties(pd, &nQueueFamilies, NULL); @@ -513,22 +565,19 @@ int isDeviceSuitable(struct RenderVulkan *vk, VkPhysicalDevice pd)  	for (uint32_t i = 0; i < nQueueFamilies; ++i) {  		printf("Queue Family %d queueCount:\t%d\n", i, queueProperties[i].queueCount);  	} -	uint32_t graphicsIndex; -	for (graphicsIndex = 0; graphicsIndex < nQueueFamilies; ++graphicsIndex) { -		if (queueProperties[graphicsIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { +	uint32_t g; +	for (g = 0; g < nQueueFamilies; ++g) { +		if (queueProperties[g].queueFlags & VK_QUEUE_GRAPHICS_BIT) {  			VkBool32 canSurface; -			vk->api->vkGetPhysicalDeviceSurfaceSupportKHR(pd, graphicsIndex, vk->surface, &canSurface); +			vk->api->vkGetPhysicalDeviceSurfaceSupportKHR(pd, g, vk->surface, &canSurface);  			if (canSurface) break;  		}  	} -	if (graphicsIndex >= nQueueFamilies) { -		/* Some esoteric devices may have separate graphics and present queue families, or none at all. -		 * An example would be a device without any video output plugs. -		 * We only support graphics and present on the same queue family. -		 */ +	if (g >= nQueueFamilies) { +		/* We only support graphics and present on the same queue family. */  		return 0;  	} -	vk->graphicsIndex = graphicsIndex; +	*graphicsIndex = g;  	return 1;  } @@ -555,6 +604,7 @@ void rvkSelectPhysicalDevice(struct RenderVulkan *vk)  		return;  	}  	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); @@ -566,24 +616,25 @@ void rvkSelectPhysicalDevice(struct RenderVulkan *vk)  	uint32_t i;  	for (i = 0; i < nDevices; ++i) { -		VkPhysicalDeviceProperties deviceProperties; -		vk->api->vkGetPhysicalDeviceProperties(devices[i], &deviceProperties); -		printf("Found physical device:\t`%s`\n", deviceProperties.deviceName); +		vk->api->vkGetPhysicalDeviceProperties(devices[i], &deviceProperties[i]); +		printf("Found physical device:\t\t`%s`\n", deviceProperties[i].deviceName);  	}  	for (i = 0; i < nDevices; ++i) { -		VkPhysicalDeviceProperties deviceProperties; -		vk->api->vkGetPhysicalDeviceProperties(devices[i], &deviceProperties); -		printf("Checking suitability for `%s`...\n", deviceProperties.deviceName); -		if (isDeviceSuitable(vk, devices[i])) { -			printf("Using physical device:\t`%s`\n", deviceProperties.deviceName); +		printf("Checking suitability for\t`%s`...\n", deviceProperties[i].deviceName); +		if (isDeviceSuitable(vk, devices[i], &vk->graphicsIndex)) { +			printf("Using physical device:\t\t`%s`\n", deviceProperties[i].deviceName); +			vk->deviceProperties = deviceProperties[i]; +			vk->physicalDevice = devices[i]; +			printf("Graphics Index:\t\t\t%d\n", vk->graphicsIndex);  			goto done;  		} -		printf("Device `%s` not suitable\n", deviceProperties.deviceName); +		printf("Device `%s` not suitable\n", deviceProperties[i].deviceName);  	}  	if (i >= nDevices) {  		rvkSetErrMsg(vk, "No suitable devices found");  	}  done: +	free(deviceProperties);  	free(devices);  } | 
