summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c334
1 files changed, 201 insertions, 133 deletions
diff --git a/main.c b/main.c
index 117d665..1cf5001 100644
--- a/main.c
+++ b/main.c
@@ -39,11 +39,10 @@ PERFORMANCE OF THIS SOFTWARE.
#if defined(_WIN32)
#include <windows.h>
-#include <vulkan/vulkan_win32.h> // to implement puglCreateVulkanSurface() on Win32
+#include <vulkan/vulkan_win32.h> // XXX Pugl: to implement puglCreateVulkanSurface() on Win32
#else
-#include <X11/Xlib.h>
-#include <vulkan/vulkan_xlib.h> // to implement puglCreateVulkanSurface() on X11
-#include "pugl/detail/x11.h" // to implement puglCreateVulkanSurface() on X11
+#include <X11/Xlib.h> // XXX Pugl: to implement puglCreateVulkanSurface() on X11
+#include <vulkan/vulkan_xlib.h> // XXX Pugl: to implement puglCreateVulkanSurface() on X11
#endif
#include "test/test_utils.h" // for printEvent()
@@ -120,6 +119,7 @@ struct VulkanDev {
PFN_vkQueuePresentKHR vkQueuePresentKHR;
};
+/** Application-specific swapchain behavior */
struct SwapchainVulkan {
VkSwapchainKHR rawSwapchain;
VkSurfaceFormatKHR surfaceFormat;
@@ -129,23 +129,34 @@ struct SwapchainVulkan {
VkImageView *imageViews;
};
+struct SemaphoreVulkan {
+ VkSemaphore imageAvailable;
+ VkSemaphore renderFinished;
+};
+
+struct FenceVulkan {
+ VkFence *swapchain; // Fences for each swapchain image
+};
+
+struct SyncVulkan {
+ struct SemaphoreVulkan semaphore;
+ struct FenceVulkan fence;
+};
+
/** Vulkan application that uses Pugl for windows and events
*
* TODO: Separate Instance from rest of application.
- * All Pugl stuff must be destroyed AFTER freeing the surface but BEFORE
- * freeing the instance. Right now we are forced to destroy them inside of
- * `rvkDestroy` even though the user creates them.
*/
struct RenderVulkan {
struct VulkanAPI *api;
struct VulkanDev *dev;
+ char *errMsg;
PuglWorld *world;
PuglView *view;
- char *errMsg;
VkInstance instance;
VkDebugReportCallbackEXT debugCallback;
VkSurfaceKHR surface;
- VkPhysicalDeviceProperties deviceProperties; // TODO: Put this on the heap
+ VkPhysicalDeviceProperties deviceProperties; // TODO: Make this a pointer. It's really big.
VkPhysicalDevice physicalDevice;
uint32_t graphicsIndex;
VkDevice device;
@@ -153,15 +164,7 @@ struct RenderVulkan {
VkCommandPool commandPool;
struct SwapchainVulkan swapchain;
VkCommandBuffer *commandBuffers;
- struct SyncVulkan {
- struct SemaphoreVulkan {
- VkSemaphore imageAvailable;
- VkSemaphore renderFinished;
- } semaphore;
- struct FenceVulkan {
- VkFence *swapchain;
- } fence;
- } sync;
+ struct SyncVulkan sync;
};
#define RVK_ERRMSG_LEN 4096
@@ -216,15 +219,15 @@ static inline int appDlclose(void *handle)
return FreeLibrary(handle);
}
-PuglStatus getRequiredInstanceExtensions(PuglWorld *world,
+/* XXX: puglGetRequiredInstanceExtensions() implementation for Win32
+ * "Get the platform-specific names of the required instance-level
+ * extensions if you want to display your images to the screen."
+ * Reminder that Vulkan is off-screen by default.
+ */
+void getRequiredInstanceExtensions(
uint32_t *pExtensionCount,
const char **const ppExtensionNames)
{
- if (!world) {
- if (pExtensionCount) *pExtensionCount = 0;
- if (ppExtensionNames) *ppExtensionNames = NULL;
- return PUGL_FAILURE;
- }
static const char *const required[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
@@ -237,33 +240,40 @@ PuglStatus getRequiredInstanceExtensions(PuglWorld *world,
} else {
*pExtensionCount = num;
}
- return PUGL_SUCCESS;
}
+/* XXX: puglCreateVulkanSurface() implementation for Win32
+ *
+ * Creating a surface is platform-specific and should be handled by Pugl
+ * with this function exposed publicly.
+ *
+ * No need to wrap vkFreeSurfaceKHR(). Creating a surface is platform
+ * specific, but freeing it is not.
+ */
VkResult createVulkanSurface(PuglView *view,
VkInstance instance,
PFN_vkGetInstanceProcAddr getInstanceProcAddrFunc,
const VkAllocationCallbacks *pAllocator,
VkSurfaceKHR *pSurface)
{
- PuglWorld *world = ((struct PuglViewImpl*)view)->world;
-
VkWin32SurfaceCreateInfoKHR createInfo = { 0 };
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
- createInfo.hinstance = GetModuleHandle(0); // FIXME (?)
+ //createInfo.hinstance = GetModuleHandle(0); // FIXME (?)
+ createInfo.hinstance = puglGetNativeWorld(view->world);
createInfo.hwnd = puglGetNativeWindow(view);
PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR =
(PFN_vkCreateWin32SurfaceKHR)getInstanceProcAddrFunc(
instance, "vkCreateWin32SurfaceKHR");
- return vkCreateWin32SurfaceKHR(
- instance, &createInfo, pAllocator, pSurface);
+ return vkCreateWin32SurfaceKHR(instance,
+ &createInfo,
+ pAllocator,
+ pSurface);
}
#else
#define VULKAN_SONAME_LATEST "libvulkan.so.1"
#include <dlfcn.h>
-// XXX: puglDlopen() and friends
static inline void *appDlopen(const char *soname)
{
return dlopen(soname, RTLD_NOW);
@@ -284,30 +294,15 @@ static inline int appDlclose(void *handle)
return dlclose(handle);
}
-/* XXX: puglGetRequiredInstanceExtensions()
- * "Get the platform-specific names of the required instance-level
+/* XXX: puglGetRequiredInstanceExtensions() implementation for Xlib
+ * "Get the platform-specific names of the required instance-level
* extensions if you want to display your images to the screen."
* Reminder that Vulkan is off-screen by default.
- *
- * TODO: Linux actually has three possible surfaces: Xlib, XCB, and Wayland.
- * This should be figured out at runtime (without using #ifdefs).
- * In which case, `world` will be used to determine which to use.
- * As of now, Pugl (and LV2! suil, etc.) only supports Xlib, but the
- * variable should be left in the function signature for forward
- * compatibility.
*/
-PuglStatus getRequiredInstanceExtensions(PuglWorld *world,
+void getRequiredInstanceExtensions(
uint32_t *pExtensionCount,
const char **const ppExtensionNames)
{
- if (!world) {
- if (pExtensionCount) *pExtensionCount = 0;
- if (ppExtensionNames) *ppExtensionNames = NULL;
- return PUGL_FAILURE;
- }
- // TODO: if (world->system == X11) { ... }
- // else if (world->system == Wayland) { ... }
- // else ...
static const char *const required[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_XLIB_SURFACE_EXTENSION_NAME
@@ -320,10 +315,9 @@ PuglStatus getRequiredInstanceExtensions(PuglWorld *world,
} else {
*pExtensionCount = num;
}
- return PUGL_SUCCESS;
}
-/* XXX: puglCreateVulkanSurface()
+/* XXX: puglCreateVulkanSurface() implementation for Xlib
*
* Creating a surface is platform-specific and should be handled by Pugl
* with this function exposed publicly.
@@ -337,11 +331,10 @@ VkResult createVulkanSurface(PuglView *view,
const VkAllocationCallbacks *pAllocator,
VkSurfaceKHR *pSurface)
{
- PuglWorld *world = ((struct PuglViewImpl*)view)->world;
-
VkXlibSurfaceCreateInfoKHR createInfo = { 0 };
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
- createInfo.dpy = ((struct PuglWorldImpl*)world)->impl->display;
+ //createInfo.dpy = ((struct PuglWorldImpl*)world)->impl->display;
+ createInfo.dpy = puglGetNativeWorld(view->world);
createInfo.window = puglGetNativeWindow(view);
PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR =
@@ -392,7 +385,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
return VK_FALSE;
}
-static VkResult rvkCreateInstance(
+static VkResult rvkCreateInternalInstance(
struct RenderVulkan *vk,
const uint32_t nLayers,
const char *const *const layers,
@@ -409,12 +402,12 @@ static VkResult rvkCreateInstance(
appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0);
uint32_t i, j, nRequired;
- getRequiredInstanceExtensions(vk->world, &nRequired, NULL);
+ getRequiredInstanceExtensions(&nRequired, NULL);
const uint32_t nExtensions = nRequired + nAdditional;
const char **const extensions = malloc(sizeof(const char*) * nExtensions);
- getRequiredInstanceExtensions(vk->world, NULL, extensions);
+ getRequiredInstanceExtensions(NULL, extensions);
for (i = nRequired, j = 0; i < nExtensions; ++i, ++j) {
extensions[i] = additionalExtensions[j];
}
@@ -443,35 +436,18 @@ static VkResult rvkCreateInstance(
return result;
}
-/** Must not be called until all derivative objects are destroyed first */
-static void rvkDestroyInstance(struct RenderVulkan *vk)
+static void rvkDestroyInternalInstance(struct RenderVulkan *vk)
{
vk->api->vkDestroyInstance(vk->instance, ALLOC_VK);
vk->instance = VK_NULL_HANDLE;
}
-void rvkDestroy(struct RenderVulkan *vk);
-
/** Create a self-contained Vulkan instance and set up a debug reporter
*
- * XXX
- *
- * At the moment `world` is not used for anything, but if/when Pugl supports
- * dynamically choosing a backend (X11, XCB, Wayland), it is anticipated that
- * `world` will contain information regarding which is in use, which will then
- * be used by `createVulkanSurface`.
- *
- * If creating a surface is handled by Pugl (`puglCreateVulkanSurface`), then
- * `PuglWorld` can remain completely opaque to the application.
- *
- * `world` is NOT internally managed by the application. It MUST be destroyed
- * separately.
- *
- * If errors occurred, the struct will be returned in an unusable state,
- * and MUST be checked via `rvkGetErrMsg`. It MUST then be destroyed via
- * `rvkDestroy`.
+ * If errors occurred, the struct will be returned in an unusable state.
+ * It MUST then be destroyed via `rvkDestroyWorld`.
* */
-int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut)
+int rvkCreateWorld(struct RenderVulkan **vkOut)
{
static const char *const instanceLayers[] = {
"VK_LAYER_KHRONOS_validation"
@@ -484,13 +460,13 @@ int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut)
struct RenderVulkan *vk = calloc(1, sizeof(*vk));
*vkOut = vk;
- if (!world) {
- rvkSetErrMsg(vk, "No PuglWorld provided");
+ vk->world = puglNewWorld();
+ if (!vk->world) {
+ rvkSetErrMsg(vk, "Could not create Pugl world");
return -1;
}
- vk->world = world;
- vk->api = calloc(1, sizeof(*vk->api));
+ vk->api = calloc(1, sizeof(*vk->api));
vk->api->handle = loadVulkanLibrary();
if (!vk->api->handle) {
rvkSetErrMsg(vk, "Error loading Vulkan shared library:\n%s\n", appDlerror());
@@ -511,8 +487,8 @@ int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut)
}
VkResult result;
- //if ((result = rvkCreateInstance(vk, 0, NULL, 0, NULL))) {
- if ((result = rvkCreateInstance(vk, nInstanceLayers, instanceLayers, nInstanceExtensions, instanceExtensions))) {
+ //if ((result = rvkCreateInternalInstance(vk, 0, NULL, 0, NULL))) {
+ if ((result = rvkCreateInternalInstance(vk, nInstanceLayers, instanceLayers, nInstanceExtensions, instanceExtensions))) {
return -1;
}
@@ -542,8 +518,6 @@ int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut)
/* Dynamically load instance-level Vulkan function pointers via `vkGetInstanceProcAddr`
*
* TODO: This could perhaps be generated by a script and put into a separate "loader" file
- *
- * Casts to `uintptr_t` as an intermediary to suppress warnings when compiling with `-Wpedantic`
*/
static const char *const strDestroySurfaceKHR = "vkDestroySurfaceKHR";
uintptr_t *ulDestroySurfaceKHR = (uintptr_t*)&vk->api->vkDestroySurfaceKHR;
@@ -656,19 +630,62 @@ int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut)
return 0;
}
-static int rvkCreateSurface(struct RenderVulkan *vk, PuglView *view)
+/** Create the view, window, and surface for this application */
+int rvkCreateSurface(struct RenderVulkan *vk, const PuglRect frame)
{
+ vk->view = puglNewView(vk->world);
+ if (!vk->view) {
+ rvkSetErrMsg(vk, "Could not create Pugl view");
+ return -1;
+ }
+ puglSetFrame(vk->view, frame);
+ puglSetHandle(vk->view, vk);
+ puglSetBackend(vk->view, puglStubBackend());
+
+ PuglStatus status;
+ if ((status = puglCreateWindow(vk->view, "Vulkan Application Using Pugl"))) {
+ rvkSetErrMsg(vk, "Could not create window: %d\n", status);
+ return -1;
+ }
+
VkResult result;
- if ((result = createVulkanSurface(view, vk->instance, vk->api->vkGetInstanceProcAddr, ALLOC_VK, &vk->surface))) {
+ if ((result = createVulkanSurface(vk->view, vk->instance, vk->api->vkGetInstanceProcAddr, ALLOC_VK, &vk->surface))) {
rvkSetErrMsg(vk, "Could not create window surface: %d\n", result);
return -1;
}
return 0;
}
+static void printQueueFamilyCapabilities(const VkQueueFlagBits queueFlags)
+{
+ const char *maybeOr = "";
+ const char *const or = " | ";
+ if (queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ printf("%sGRAPHICS", maybeOr);
+ maybeOr = or;
+ }
+ if (queueFlags & VK_QUEUE_COMPUTE_BIT) {
+ printf("%sCOMPUTE", maybeOr);
+ maybeOr = or;
+ }
+ if (queueFlags & VK_QUEUE_TRANSFER_BIT) {
+ printf("%sTRANSFER", maybeOr);
+ maybeOr = or;
+ }
+ if (queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) {
+ printf("%sSPARSE_BINDING", maybeOr);
+ maybeOr = or;
+ }
+ if (queueFlags & VK_QUEUE_PROTECTED_BIT) {
+ printf("%sPROTECTED", maybeOr);
+ maybeOr = or;
+ }
+ printf("\n");
+}
+
/** Checks if a particular physical device is suitable for this application.
*
- * This function is referentially transparent.
+ * This function is referentially transparent (aside from printing to stdout).
*
* Choosing a physical device is an *extremely* application-specific procedure.
*
@@ -698,9 +715,9 @@ static int rvkCreateSurface(struct RenderVulkan *vk, PuglView *view)
* 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.
+ * more efficiently. Queues must be submitted to from a single
+ * thread at a time, 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
@@ -725,6 +742,10 @@ static bool rvkIsDeviceSuitable(const struct RenderVulkan *const vk,
for (uint32_t i = 0; i < nQueueFamilies; ++i) {
printf("Queue Family %d queueCount:\t%d\n", i, queueProperties[i].queueCount);
}
+ for (uint32_t i = 0; i < nQueueFamilies; ++i) {
+ printf("Queue family %d queueFlags:\t", i);
+ printQueueFamilyCapabilities(queueProperties[i].queueFlags);
+ }
uint32_t g;
for (g = 0; g < nQueueFamilies; ++g) {
if (queueProperties[g].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
@@ -812,7 +833,7 @@ int rvkSelectPhysicalDevice(struct RenderVulkan *vk)
vk->deviceProperties = deviceProperties[i];
vk->physicalDevice = devices[i];
vk->graphicsIndex = graphicsIndex;
- printf("Graphics Index:\t\t\t%d\n", vk->graphicsIndex);
+ printf("Using GRAPHICS family index:\t%d\n", vk->graphicsIndex);
goto done;
}
printf("Device `%s` not suitable\n", deviceProperties[i].deviceName);
@@ -1075,11 +1096,38 @@ int rvkOpenDevice(struct RenderVulkan *vk)
return 0;
}
+static char *strPresentMode(const VkPresentModeKHR presentMode)
+{
+ switch (presentMode) {
+ case VK_PRESENT_MODE_IMMEDIATE_KHR:
+ return "Immediate";
+ case VK_PRESENT_MODE_MAILBOX_KHR:
+ return "Mailbox";
+ case VK_PRESENT_MODE_FIFO_KHR:
+ return "FIFO";
+ case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
+ return "FIFO relaxed";
+ default:
+ return "Other";
+ }
+}
+
+static bool isPresentModeSupported(const VkPresentModeKHR *const presentModes,
+ const uint32_t nPresentModes, const VkPresentModeKHR want)
+{
+ for (uint32_t i = 0; i < nPresentModes; ++i) {
+ if (presentModes[i] == want) {
+ return true;
+ }
+ }
+ return false;
+}
+
static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height)
{
VkSurfaceCapabilitiesKHR surfaceCapabilities;
VkSurfaceFormatKHR *surfaceFormats;
- VkPresentModeKHR *presentModes; // TODO
+ VkPresentModeKHR *presentModes;
VkResult result;
if ((result = vk->api->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
vk->physicalDevice, vk->surface, &surfaceCapabilities))) {
@@ -1126,8 +1174,31 @@ static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height)
return -1;
}
- // TODO
- VkPresentModeKHR presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
+ uint32_t nPresentModes;
+ vk->api->vkGetPhysicalDeviceSurfacePresentModesKHR(vk->physicalDevice, vk->surface, &nPresentModes, NULL);
+ if (!nPresentModes) {
+ rvkSetErrMsg(vk, "No present modes available");
+ return -1;
+ }
+ presentModes = malloc(nPresentModes * sizeof(*presentModes));
+ vk->api->vkGetPhysicalDeviceSurfacePresentModesKHR(vk->physicalDevice,
+ vk->surface, &nPresentModes, presentModes);
+
+ VkPresentModeKHR presentMode;
+ for (i = 0; i < nPresentModes; ++i) {
+ presentMode = presentModes[i];
+ printf("Found present mode:\t\t%s\t(%d)\n", strPresentMode(presentMode), presentMode);
+ }
+
+ if (isPresentModeSupported(presentModes, nPresentModes, VK_PRESENT_MODE_MAILBOX_KHR)) {
+ presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
+ } else if (isPresentModeSupported(presentModes, nPresentModes, VK_PRESENT_MODE_IMMEDIATE_KHR)) {
+ presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
+ } else {
+ presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ }
+ free(presentModes);
+ printf("Using present mode:\t\t%s\t(%d)\n", strPresentMode(presentMode), presentMode);
// TODO: Clamp
vk->swapchain.extent.width = width;
@@ -1405,7 +1476,7 @@ static void rvkCloseDevice(struct RenderVulkan *vk)
vk->dev->vkDestroyDevice(vk->device, ALLOC_VK);
} else {
/* This is only theoretical, because we must load the "destroy"
- * function *after* we create the device
+ * function AFTER we create the device
*/
fprintf(stderr, "Fatal: Unable to destroy logical device (missing function pointer)\n");
}
@@ -1416,7 +1487,7 @@ static void rvkCloseDevice(struct RenderVulkan *vk)
}
/** This must work no matter the current state of `vk` */
-void rvkDestroy(struct RenderVulkan *vk)
+void rvkDestroyApplication(struct RenderVulkan *vk)
{
if (vk) {
rvkCloseDevice(vk);
@@ -1424,21 +1495,30 @@ void rvkDestroy(struct RenderVulkan *vk)
vk->api->vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK);
vk->surface = VK_NULL_HANDLE;
}
- /* PuglView must be freed AFTER surface but BEFORE instance destroy */
if (vk->view) {
+ /* PuglView must be freed AFTER surface but BEFORE instance destroy */
puglFreeView(vk->view);
vk->view = NULL;
}
+ }
+}
+
+/** This must be called AFTER `rvkDestroyApplication` if it was created */
+void rvkDestroyWorld(struct RenderVulkan *vk)
+{
+ if (vk) {
+ if (vk->world) {
+ /* PuglWorld must be unloaded AFTER PuglView but BEFORE instance destroy */
+ puglFreeWorld(vk->world);
+ vk->world = NULL;
+ }
if (vk->debugCallback) {
/* `vk->debugCallback` implies `vk->api` and all instance functions loaded */
vk->api->vkDestroyDebugReportCallbackEXT(vk->instance, vk->debugCallback, ALLOC_VK);
vk->debugCallback = VK_NULL_HANDLE;
}
- /* PuglWorld must be unloaded AFTER PuglView but BEFORE instance destroy */
- puglFreeWorld(vk->world);
- vk->world = NULL;
if (vk->instance) {
- rvkDestroyInstance(vk);
+ rvkDestroyInternalInstance(vk);
vk->instance = VK_NULL_HANDLE;
}
if (vk->api) {
@@ -1462,10 +1542,8 @@ void rvkDestroy(struct RenderVulkan *vk)
static void rvkFatal(struct RenderVulkan *vk)
{
fprintf(stderr, "%s\n", rvkGetErrMsg(vk));
- rvkDestroy(vk);
- if (vk->world) {
- puglFreeWorld(vk->world);
- }
+ rvkDestroyApplication(vk);
+ rvkDestroyWorld(vk);
printf("Aborting gracefully\n");
exit(1);
}
@@ -1482,6 +1560,7 @@ PuglStatus onDisplay(PuglView *view)
uint32_t imageIndex;
VkResult result;
+
if ((result = vk->dev->vkAcquireNextImageKHR(
vk->device,
vk->swapchain.rawSwapchain,
@@ -1493,11 +1572,12 @@ PuglStatus onDisplay(PuglView *view)
return PUGL_FAILURE;
}
- /* If running continuously, Vulkan can blast the GPU with rendering work
- * faster than it can get around to presenting it, causing RAM usage to
- * grow indefinitely. We use fences to limit the number of frames to the
- * number of swapchain images. This will also be required later when
- * flushing persistently mapped uniform buffer ranges anyway.
+ /* If running continuously, Vulkan can blast the queue with rendering
+ * work faster than the GPU can get around to doing it, causing RAM
+ * usage to grow indefinitely. We use fences to limit the number of
+ * submitted frames to the number of swapchain images. These fences will
+ * be required later anyway when flushing persistently mapped uniform
+ * buffer ranges.
*/
vk->dev->vkWaitForFences(vk->device,
1, &vk->sync.fence.swapchain[imageIndex],
@@ -1561,27 +1641,14 @@ int main()
/* The Mesa Vulkan drivers require this to be called */
XInitThreads();
#endif
- PuglWorld *world = puglNewWorld();
-
/* Vulkan application that uses Pugl for windows and events */
struct RenderVulkan *vk;
- CHECK_RVK(vk, rvkCreate(world, &vk));
+ CHECK_RVK(vk, rvkCreateWorld(&vk));
printf("Created Vulkan Instance Successfully\n");
- PuglView *view = puglNewView(world);
- const PuglRect frame = { 0, 0, 800, 600 };
- puglSetFrame(view, frame);
- puglSetHandle(view, vk);
- puglSetBackend(view, puglStubBackend());
- PuglStatus status;
- if ((status = puglCreateWindow(view, "Vulkan Application Using Pugl"))) {
- fprintf(stderr, "Could not create window: %d\n", status);
- rvkFatal(vk);
- }
- vk->view = view;
-
- CHECK_RVK(vk, rvkCreateSurface(vk, view));
+ const PuglRect frame = { 0, 0, 800, 600 };
+ CHECK_RVK(vk, rvkCreateSurface(vk, frame));
CHECK_RVK(vk, rvkSelectPhysicalDevice(vk));
CHECK_RVK(vk, rvkOpenDevice(vk));
CHECK_RVK(vk, rvkCreateSwapchain(vk, frame.width, frame.height));
@@ -1589,17 +1656,18 @@ int main()
printf("Opened Vulkan Device Successfully\n");
- puglSetEventFunc(view, onEvent);
+ puglSetEventFunc(vk->view, onEvent);
//PuglFpsPrinter fpsPrinter = { puglGetTime(world) };
- puglShowWindow(view);
+ puglShowWindow(vk->view);
while (running) {
- puglPollEvents(world, -1);
+ puglPollEvents(vk->world, -1);
//puglPostRedisplay(view);
- puglDispatchEvents(world);
+ puglDispatchEvents(vk->world);
//puglPrintFps(world, &fpsPrinter, &framesDrawn);
}
- rvkDestroy(vk);
+ rvkDestroyApplication(vk);
+ rvkDestroyWorld(vk);
printf("Exiting gracefully\n");
return 0;
}