summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorJordan Halase <jordan@halase.me>2019-11-01 20:27:23 -0500
committerJordan Halase <jordan@halase.me>2019-11-01 20:27:23 -0500
commit3af08aac52d6c382f5c61be66f1fe9ca1fcebe4b (patch)
tree3e461429b8405a24f69e83d64b0e002694d62e76 /main.c
parent9fbe9c0edb826c65efd204b34264f42dd77fd3d4 (diff)
Implement basic screen clearing functionality
Diffstat (limited to 'main.c')
-rw-r--r--main.c352
1 files changed, 303 insertions, 49 deletions
diff --git a/main.c b/main.c
index b40e413..eed82b1 100644
--- a/main.c
+++ b/main.c
@@ -39,21 +39,22 @@ PERFORMANCE OF THIS SOFTWARE.
#if defined(_WIN32)
#include <windows.h>
-#include <vulkan/vulkan_win32.h>
+#include <vulkan/vulkan_win32.h> // to implement puglCreateVulkanSurface() on Win32
#else
#include <X11/Xlib.h>
-#include <vulkan/vulkan_xlib.h>
-#include "pugl/detail/x11.h"
+#include <vulkan/vulkan_xlib.h> // to implement puglCreateVulkanSurface() on X11
+#include "pugl/detail/x11.h" // to implement puglCreateVulkanSurface() on X11
#endif
-#include "test/test_utils.h" // for printEvent()
+#include "test/test_utils.h" // for printEvent()
#include "pugl/pugl.h"
#include "pugl/pugl_stub_backend.h"
#define STB_SPRINTF_IMPLEMENTATION
-#include "stb_sprintf.h"
+#include "stb_sprintf.h" // a better, cross-platform sprintf() for error formatting
+/* Thread-local storage for ad-hoc dlerr() on Windows */
#if defined(__GNUC__)
#define APP_THREAD_LOCAL __thread
#else
@@ -69,7 +70,7 @@ PERFORMANCE OF THIS SOFTWARE.
/** Instance-level Vulkan functions and handle */
struct VulkanAPI {
- void *handle;
+ void *handle;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
PFN_vkCreateInstance vkCreateInstance;
PFN_vkDestroyInstance vkDestroyInstance;
@@ -104,7 +105,14 @@ struct VulkanDev {
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
+ PFN_vkEndCommandBuffer vkEndCommandBuffer;
+ PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
PFN_vkCmdClearColorImage vkCmdClearColorImage;
+ PFN_vkCreateSemaphore vkCreateSemaphore;
+ PFN_vkDestroySemaphore vkDestroySemaphore;
+ PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
+ PFN_vkQueueSubmit vkQueueSubmit;
+ PFN_vkQueuePresentKHR vkQueuePresentKHR;
};
struct SwapchainVulkan {
@@ -118,10 +126,10 @@ struct SwapchainVulkan {
/** Vulkan application that uses Pugl for windows and events */
struct RenderVulkan {
- struct VulkanAPI *api;
- struct VulkanDev *dev;
- PuglWorld *world;
- char *errMsg;
+ struct VulkanAPI *api;
+ struct VulkanDev *dev;
+ PuglWorld *world;
+ char *errMsg;
VkInstance instance;
VkDebugReportCallbackEXT debugCallback;
VkSurfaceKHR surface;
@@ -133,6 +141,12 @@ struct RenderVulkan {
VkCommandPool commandPool;
struct SwapchainVulkan swapchain;
VkCommandBuffer *commandBuffers;
+ struct SyncVulkan {
+ struct SemaphoreVulkan {
+ VkSemaphore imageAvailable;
+ VkSemaphore renderFinished;
+ } semaphore;
+ } sync;
};
#define RVK_ERRMSG_LEN 4096
@@ -171,7 +185,8 @@ static inline char *appDlerror()
// TODO: Print a more informative string. Error codes are annoying.
DWORD errCode = GetLastError();
static APP_THREAD_LOCAL char errStr[64];
- stbsp_snprintf(errStr, sizeof(errStr), "Dynamic Library Error: %d", errCode);
+ stbsp_snprintf(errStr, sizeof(errStr),
+ "Dynamic Library Error: %d", errCode);
return errStr;
}
@@ -217,14 +232,18 @@ VkResult createVulkanSurface(PuglView *view,
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.hwnd = puglGetNativeWindow(view);
- PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
- uintptr_t *const ulCreateWin32SurfaceKHR = (uintptr_t*)&vkCreateWin32SurfaceKHR;
- *ulCreateWin32SurfaceKHR = (uintptr_t)getInstanceProcAddrFunc(instance, "vkCreateWin32SurfaceKHR");
- return vkCreateWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface);
+
+ PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR =
+ (PFN_vkCreateWin32SurfaceKHR)getInstanceProcAddrFunc(
+ instance, "vkCreateWin32SurfaceKHR");
+
+ return vkCreateWin32SurfaceKHR(
+ instance, &createInfo, pAllocator, pSurface);
}
#else
#define VULKAN_SONAME_LATEST "libvulkan.so.1"
@@ -271,7 +290,9 @@ PuglStatus getRequiredInstanceExtensions(PuglWorld *world,
if (ppExtensionNames) *ppExtensionNames = NULL;
return PUGL_FAILURE;
}
- // TODO: if (world->system == X11) { ... } else if (world->system == Wayland) { ... } else ...
+ // 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
@@ -302,32 +323,38 @@ VkResult createVulkanSurface(PuglView *view,
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.window = puglGetNativeWindow(view);
- PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR;
- uintptr_t *const ulCreateXlibSurfaceKHR = (uintptr_t*)&vkCreateXlibSurfaceKHR;
- *ulCreateXlibSurfaceKHR = (uintptr_t)getInstanceProcAddrFunc(instance, "vkCreateXlibSurfaceKHR");
- return vkCreateXlibSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
+
+ PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR =
+ (PFN_vkCreateXlibSurfaceKHR)getInstanceProcAddrFunc(
+ instance, "vkCreateXlibSurfaceKHR");
+
+ return vkCreateXlibSurfaceKHR(instance,
+ &createInfo,
+ pAllocator,
+ pSurface);
}
#endif
-void *loadVulkanLibrary(const char *prefix)
+static void *loadVulkanLibrary()
{
- (void)prefix; // TODO
void *handle = appDlopen(VULKAN_SONAME_LATEST);
return handle;
}
-void loadVulkanGetInstanceProcAddrFunc(void *handle,
+static void loadVulkanGetInstanceProcAddrFunc(void *handle,
PFN_vkGetInstanceProcAddr *getInstanceProcAddrFunc)
{
- uintptr_t *ulGetInstanceProcAddrFunc = (uintptr_t*)getInstanceProcAddrFunc;
- *ulGetInstanceProcAddrFunc = (uintptr_t)appDlsym(handle, "vkGetInstanceProcAddr");
+ *getInstanceProcAddrFunc = (PFN_vkGetInstanceProcAddr)appDlsym(
+ handle,
+ "vkGetInstanceProcAddr");
}
-int unloadVulkanLibrary(void *handle)
+static int unloadVulkanLibrary(void *handle)
{
if (handle) {
return appDlclose(handle);
@@ -350,9 +377,12 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
return VK_FALSE;
}
-static VkResult rvkCreateInstance(struct RenderVulkan *vk,
- const uint32_t nLayers, const char *const *const layers,
- const uint32_t nAdditional, const char *const *const additionalExtensions)
+static VkResult rvkCreateInstance(
+ struct RenderVulkan *vk,
+ const uint32_t nLayers,
+ const char *const *const layers,
+ const uint32_t nAdditional,
+ const char *const *const additionalExtensions)
{
VkApplicationInfo appInfo = { 0 };
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
@@ -446,7 +476,7 @@ int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut)
vk->world = world;
vk->api = calloc(1, sizeof(*vk->api));
- vk->api->handle = loadVulkanLibrary(NULL);
+ vk->api->handle = loadVulkanLibrary();
if (!vk->api->handle) {
rvkSetErrMsg(vk, "Error loading Vulkan shared library:\n%s\n", appDlerror());
return -1;
@@ -838,10 +868,110 @@ static int rvkLoadDeviceFunctions(struct RenderVulkan *vk, VkDevice device)
return -1;
}
+ static const char *const _vkGetSwapchainImagesKHR = "vkGetSwapchainImagesKHR";
+ vk->dev->vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)vk->api->vkGetDeviceProcAddr(device, _vkGetSwapchainImagesKHR);
+ if (!vk->dev->vkGetSwapchainImagesKHR) {
+ rvkSetErrMsg(vk, strErrLd, _vkGetSwapchainImagesKHR);
+ return -1;
+ }
+
+ static const char *const _vkCreateImageView = "vkCreateImageView";
+ vk->dev->vkCreateImageView = (PFN_vkCreateImageView)vk->api->vkGetDeviceProcAddr(device, _vkCreateImageView);
+ if (!vk->dev->vkCreateImageView) {
+ rvkSetErrMsg(vk, strErrLd, _vkCreateImageView);
+ return -1;
+ }
+
+ static const char *const _vkDestroyImageView = "vkDestroyImageView";
+ vk->dev->vkDestroyImageView = (PFN_vkDestroyImageView)vk->api->vkGetDeviceProcAddr(device, _vkDestroyImageView);
+ if (!vk->dev->vkDestroyImageView) {
+ rvkSetErrMsg(vk, strErrLd, _vkDestroyImageView);
+ return -1;
+ }
+
+ static const char *const _vkAllocateCommandBuffers = "vkAllocateCommandBuffers";
+ vk->dev->vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)vk->api->vkGetDeviceProcAddr(device, _vkAllocateCommandBuffers);
+ if (!vk->dev->vkAllocateCommandBuffers) {
+ rvkSetErrMsg(vk, strErrLd, _vkAllocateCommandBuffers);
+ return -1;
+ }
+
+ static const char *const _vkFreeCommandBuffers = "vkFreeCommandBuffers";
+ vk->dev->vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)vk->api->vkGetDeviceProcAddr(device, _vkFreeCommandBuffers);
+ if (!vk->dev->vkFreeCommandBuffers) {
+ rvkSetErrMsg(vk, strErrLd, _vkFreeCommandBuffers);
+ return -1;
+ }
+
+ static const char *const _vkBeginCommandBuffer = "vkBeginCommandBuffer";
+ vk->dev->vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)vk->api->vkGetDeviceProcAddr(device, _vkBeginCommandBuffer);
+ if (!vk->dev->vkBeginCommandBuffer) {
+ rvkSetErrMsg(vk, strErrLd, _vkBeginCommandBuffer);
+ return -1;
+ }
+
+ static const char *const _vkEndCommandBuffer = "vkEndCommandBuffer";
+ vk->dev->vkEndCommandBuffer = (PFN_vkEndCommandBuffer)vk->api->vkGetDeviceProcAddr(device, _vkEndCommandBuffer);
+ if (!vk->dev->vkEndCommandBuffer) {
+ rvkSetErrMsg(vk, strErrLd, _vkEndCommandBuffer);
+ return -1;
+ }
+
+ static const char *const _vkCmdPipelineBarrier = "vkCmdPipelineBarrier";
+ vk->dev->vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)vk->api->vkGetDeviceProcAddr(device, _vkCmdPipelineBarrier);
+ if (!vk->dev->vkCmdPipelineBarrier) {
+ rvkSetErrMsg(vk, strErrLd, _vkCmdPipelineBarrier);
+ return -1;
+ }
+
+ static const char *const _vkCmdClearColorImage = "vkCmdClearColorImage";
+ vk->dev->vkCmdClearColorImage = (PFN_vkCmdClearColorImage)vk->api->vkGetDeviceProcAddr(device, _vkCmdClearColorImage);
+ if (!vk->dev->vkCmdClearColorImage) {
+ rvkSetErrMsg(vk, strErrLd, _vkCmdClearColorImage);
+ return -1;
+ }
+
+ static const char *const _vkCreateSemaphore = "vkCreateSemaphore";
+ vk->dev->vkCreateSemaphore = (PFN_vkCreateSemaphore)vk->api->vkGetDeviceProcAddr(device, _vkCreateSemaphore);
+ if (!vk->dev->vkCreateSemaphore) {
+ rvkSetErrMsg(vk, strErrLd, _vkCreateSemaphore);
+ return -1;
+ }
+
+ static const char *const _vkDestroySemaphore = "vkDestroySemaphore";
+ vk->dev->vkDestroySemaphore = (PFN_vkDestroySemaphore)vk->api->vkGetDeviceProcAddr(device, _vkDestroySemaphore);
+ if (!vk->dev->vkDestroySemaphore) {
+ rvkSetErrMsg(vk, strErrLd, _vkDestroySemaphore);
+ return -1;
+ }
+
+ static const char *const _vkAcquireNextImageKHR = "vkAcquireNextImageKHR";
+ vk->dev->vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)vk->api->vkGetDeviceProcAddr(device, _vkAcquireNextImageKHR);
+ if (!vk->dev->vkAcquireNextImageKHR) {
+ rvkSetErrMsg(vk, strErrLd, _vkAcquireNextImageKHR);
+ return -1;
+ }
+
+ static const char *const _vkQueueSubmit = "vkQueueSubmit";
+ vk->dev->vkQueueSubmit = (PFN_vkQueueSubmit)vk->api->vkGetDeviceProcAddr(device, _vkQueueSubmit);
+ if (!vk->dev->vkQueueSubmit) {
+ rvkSetErrMsg(vk, strErrLd, _vkQueueSubmit);
+ return -1;
+ }
+
+ static const char *const _vkQueuePresentKHR = "vkQueuePresentKHR";
+ vk->dev->vkQueuePresentKHR = (PFN_vkQueuePresentKHR)vk->api->vkGetDeviceProcAddr(device, _vkQueuePresentKHR);
+ if (!vk->dev->vkQueuePresentKHR) {
+ rvkSetErrMsg(vk, strErrLd, _vkQueuePresentKHR);
+ return -1;
+ }
+
return 0;
}
-/** Opens the logical device, retrieves queue(s), and creates command pool for this application. */
+/** Opens the logical device, retrieves queue(s), and creates the command pool
+ * for this application.
+ */
int rvkOpenDevice(struct RenderVulkan *vk)
{
if (vk->device) {
@@ -860,8 +990,9 @@ int rvkOpenDevice(struct RenderVulkan *vk)
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.queueCreateInfoCount = 1;
createInfo.pQueueCreateInfos = &queueCreateInfo;
- /* `enabledLayerCount` and `ppEnabledLayerNames` are ignored by modern Vulkan implementations.
- * TODO: But maybe it is a good idea to support the older implementations.
+ /* `enabledLayerCount` and `ppEnabledLayerNames` are ignored by modern
+ * Vulkan implementations.
+ * TODO: But maybe we should support the older implementations.
*/
createInfo.enabledExtensionCount = 1;
createInfo.ppEnabledExtensionNames = &swapchainName;
@@ -968,7 +1099,7 @@ static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height)
createInfo.imageFormat = vk->swapchain.surfaceFormat.format;
createInfo.imageExtent = vk->swapchain.extent;
createInfo.imageArrayLayers = 1;
- createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.preTransform = surfaceCapabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
@@ -995,7 +1126,7 @@ static VkResult createSwapchainImageViews(VkDevice device,
dev->vkGetSwapchainImagesKHR(device, swapchain->rawSwapchain, &swapchain->nImages, NULL);
swapchain->images = calloc(swapchain->nImages, sizeof(*swapchain->images));
dev->vkGetSwapchainImagesKHR(device, swapchain->rawSwapchain, &swapchain->nImages, swapchain->images);
- swapchain->imageViews = calloc(swapchain->nImages, sizeof(*swapchain->imageViews));
+ //swapchain->imageViews = calloc(swapchain->nImages, sizeof(*swapchain->imageViews));
VkResult result;
for (uint32_t i = 0; i < swapchain->nImages; ++i) {
@@ -1013,9 +1144,9 @@ static VkResult createSwapchainImageViews(VkDevice device,
createInfo.subresourceRange.levelCount = 1;
createInfo.subresourceRange.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1;
- if ((result = dev->vkCreateImageView(device, &createInfo, ALLOC_VK, &swapchain->imageViews[i]))) {
- return result;
- }
+ // if ((result = dev->vkCreateImageView(device, &createInfo, ALLOC_VK, &swapchain->imageViews[i]))) {
+ // return result;
+ // }
}
return VK_SUCCESS;
}
@@ -1053,10 +1184,10 @@ static void freeCommandBuffers(struct RenderVulkan *vk)
static int recordCommandBuffers(struct RenderVulkan *vk)
{
VkClearColorValue clearValue = { 0 };
- clearValue.uint32[0] = 128;
- clearValue.uint32[1] = 128;
- clearValue.uint32[2] = 128;
- clearValue.uint32[2] = 255;
+ clearValue.float32[0] = 1.0f; // R
+ clearValue.float32[1] = 0.0f; // G
+ clearValue.float32[2] = 0.5f; // B
+ clearValue.float32[3] = 1.0f; // A
VkImageSubresourceRange range = { 0 };
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@@ -1065,14 +1196,84 @@ static int recordCommandBuffers(struct RenderVulkan *vk)
range.baseArrayLayer = 0;
range.layerCount = 1;
+ VkCommandBufferBeginInfo beginInfo = { 0 };
+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+
for (uint32_t i = 0; i < vk->swapchain.nImages; ++i) {
- VkCommandBufferBeginInfo beginInfo = { 0 };
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+ VkImageMemoryBarrier toClearBarrier = { 0 };
+ toClearBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ toClearBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+ toClearBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ toClearBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ toClearBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ toClearBarrier.srcQueueFamilyIndex = vk->graphicsIndex;
+ toClearBarrier.dstQueueFamilyIndex = vk->graphicsIndex;
+ toClearBarrier.image = vk->swapchain.images[i];
+ toClearBarrier.subresourceRange = range;
+
+ VkImageMemoryBarrier toPresentBarrier = { 0 };
+ toPresentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ toPresentBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ toPresentBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
+ toPresentBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
+ toPresentBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ toPresentBarrier.srcQueueFamilyIndex = vk->graphicsIndex;
+ toPresentBarrier.dstQueueFamilyIndex = vk->graphicsIndex;
+ toPresentBarrier.image = vk->swapchain.images[i];
+ toPresentBarrier.subresourceRange = range;
+
vk->dev->vkBeginCommandBuffer(vk->commandBuffers[i], &beginInfo);
+ vk->dev->vkCmdPipelineBarrier(vk->commandBuffers[i],
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ 0,
+ 0, NULL,
+ 0, NULL,
+ 1, &toClearBarrier);
vk->dev->vkCmdClearColorImage(vk->commandBuffers[i], vk->swapchain.images[i],
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, &clearValue, 1, &range);
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue, 1, &range);
+ vk->dev->vkCmdPipelineBarrier(vk->commandBuffers[i],
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+ 0,
+ 0, NULL,
+ 0, NULL,
+ 1, &toPresentBarrier);
+ vk->dev->vkEndCommandBuffer(vk->commandBuffers[i]);
+ }
+
+ return 0;
+}
+
+int rvkCreateSwapchain(struct RenderVulkan *vk, const int width, const int height)
+{
+ if (rvkCreateRawSwapchain(vk, width, height)) {
+ return -1;
+ }
+ VkResult result;
+ if ((result = createSwapchainImageViews(vk->device, vk->dev, &vk->swapchain))) {
+ rvkSetErrMsg(vk, "Could not create swapchain image views: %d", result);
+ return -1;
+ }
+ if ((result = allocateCommandBuffers(vk))) {
+ rvkSetErrMsg(vk, "Could not allocate command buffers: %d", result);
+ return -1;
+ }
+ if (recordCommandBuffers(vk)) {
+ return -1;
}
+ return 0;
+}
+
+/** Creates any semaphores or fences for this application. */
+int rvkCreateSyncObjects(struct RenderVulkan *vk)
+{
+ VkSemaphoreCreateInfo semaphoreInfo = { 0 };
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ vk->dev->vkCreateSemaphore(vk->device, &semaphoreInfo, ALLOC_VK, &vk->sync.semaphore.imageAvailable);
+ vk->dev->vkCreateSemaphore(vk->device, &semaphoreInfo, ALLOC_VK, &vk->sync.semaphore.renderFinished);
+ return 0;
}
/** This must work no matter the current state of `vk` */
@@ -1120,10 +1321,61 @@ static void rvkFatal(struct RenderVulkan *vk)
int running = 1;
+PuglStatus onDisplay(PuglView *view)
+{
+ struct RenderVulkan *vk = puglGetHandle(view);
+
+ uint32_t imageIndex;
+ VkResult result;
+ if ((result = vk->dev->vkAcquireNextImageKHR(
+ vk->device,
+ vk->swapchain.rawSwapchain,
+ UINT64_MAX,
+ vk->sync.semaphore.imageAvailable,
+ VK_NULL_HANDLE,
+ &imageIndex))) {
+ rvkSetErrMsg(vk, "Could not acquire swapchain image: %d", result);
+ return PUGL_FAILURE;
+ }
+
+ VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ VkSubmitInfo submitInfo = { 0 };
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submitInfo.waitSemaphoreCount = 1;
+ submitInfo.pWaitSemaphores = &vk->sync.semaphore.imageAvailable;
+ submitInfo.pWaitDstStageMask = &waitStage;
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &vk->commandBuffers[imageIndex];
+ submitInfo.signalSemaphoreCount = 1;
+ submitInfo.pSignalSemaphores = &vk->sync.semaphore.renderFinished;
+
+ if ((result = vk->dev->vkQueueSubmit(vk->graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE))) {
+ rvkSetErrMsg(vk, "Could not submit to queue: %d", result);
+ return PUGL_FAILURE;
+ }
+
+ VkPresentInfoKHR presentInfo = { 0 };
+ presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+ presentInfo.waitSemaphoreCount = 1;
+ presentInfo.pWaitSemaphores = &vk->sync.semaphore.renderFinished;
+ presentInfo.swapchainCount = 1;
+ presentInfo.pSwapchains = &vk->swapchain.rawSwapchain;
+ presentInfo.pImageIndices = &imageIndex;
+ presentInfo.pResults = NULL;
+
+ vk->dev->vkQueuePresentKHR(vk->graphicsQueue, &presentInfo);
+
+ return PUGL_SUCCESS;
+}
+
PuglStatus onEvent(PuglView *view, const PuglEvent *e)
{
printEvent(e, "Event:\t", true);
switch (e->type) {
+ case PUGL_EXPOSE:
+ onDisplay(view);
+ break;
case PUGL_CLOSE:
running = 0;
break;
@@ -1142,7 +1394,7 @@ int main()
PuglWorld *world = puglNewWorld();
/* Vulkan application that uses Pugl for windows and events */
- struct RenderVulkan *vk = NULL;
+ struct RenderVulkan *vk;
CHECK_RVK(vk, rvkCreate(world, &vk));
printf("Created Vulkan Instance Successfully\n");
@@ -1150,6 +1402,7 @@ int main()
PuglView *view = puglNewView(world);
const PuglRect frame = { 0, 0, 800, 600 };
puglSetFrame(view, frame);
+ puglSetHandle(view, vk);
puglSetBackend(view, puglStubBackend());
PuglStatus status;
@@ -1162,7 +1415,8 @@ int main()
CHECK_RVK(vk, rvkCreateSurface(vk, view));
CHECK_RVK(vk, rvkSelectPhysicalDevice(vk));
CHECK_RVK(vk, rvkOpenDevice(vk));
- CHECK_RVK(vk, rvkCreateRawSwapchain(vk, frame.width, frame.height));
+ CHECK_RVK(vk, rvkCreateSwapchain(vk, frame.width, frame.height));
+ CHECK_RVK(vk, rvkCreateSyncObjects(vk));
printf("Opened Vulkan Device Successfully\n");