From 40e48dce46f1c0009ee57d7e00def483fda6add6 Mon Sep 17 00:00:00 2001 From: Jordan Halase Date: Tue, 29 Oct 2019 13:07:21 -0500 Subject: Overhaul --- .gitignore | 1 + CMakeLists.txt | 17 ++++++++++ compiling.txt | 13 ++++++++ main.c | 101 +++++++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 107 insertions(+), 25 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 compiling.txt diff --git a/.gitignore b/.gitignore index b683a51..eb8f265 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/main.c b/main.c index 30d2933..3aba8ce 100644 --- a/main.c +++ b/main.c @@ -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 +// 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); } -- cgit v1.2.1