summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt17
-rw-r--r--compiling.txt13
-rw-r--r--main.c101
4 files changed, 107 insertions, 25 deletions
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 <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);
}