From 3af08aac52d6c382f5c61be66f1fe9ca1fcebe4b Mon Sep 17 00:00:00 2001 From: Jordan Halase Date: Fri, 1 Nov 2019 20:27:23 -0500 Subject: Implement basic screen clearing functionality --- main.c | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file 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 -#include +#include // to implement puglCreateVulkanSurface() on Win32 #else #include -#include -#include "pugl/detail/x11.h" +#include // 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"); -- cgit v1.2.1