From 9fbe9c0edb826c65efd204b34264f42dd77fd3d4 Mon Sep 17 00:00:00 2001 From: Jordan Halase Date: Fri, 1 Nov 2019 16:35:33 -0500 Subject: Add more functionality --- main.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 230 insertions(+), 5 deletions(-) diff --git a/main.c b/main.c index d117d17..b40e413 100644 --- a/main.c +++ b/main.c @@ -84,15 +84,36 @@ struct VulkanAPI { PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; PFN_vkCreateDevice vkCreateDevice; PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; }; /** Device-level Vulkan functions */ struct VulkanDev { - PFN_vkDestroyDevice vkDestroyDevice; - PFN_vkDeviceWaitIdle vkDeviceWaitIdle; - PFN_vkGetDeviceQueue vkGetDeviceQueue; - PFN_vkCreateCommandPool vkCreateCommandPool; - PFN_vkDestroyCommandPool vkDestroyCommandPool; + PFN_vkDestroyDevice vkDestroyDevice; + PFN_vkDeviceWaitIdle vkDeviceWaitIdle; + PFN_vkGetDeviceQueue vkGetDeviceQueue; + PFN_vkCreateCommandPool vkCreateCommandPool; + PFN_vkDestroyCommandPool vkDestroyCommandPool; + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkCreateImageView vkCreateImageView; + PFN_vkDestroyImageView vkDestroyImageView; + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; + PFN_vkFreeCommandBuffers vkFreeCommandBuffers; + PFN_vkBeginCommandBuffer vkBeginCommandBuffer; + PFN_vkCmdClearColorImage vkCmdClearColorImage; +}; + +struct SwapchainVulkan { + VkSwapchainKHR rawSwapchain; + VkSurfaceFormatKHR surfaceFormat; + uint32_t nImages; + VkExtent2D extent; + VkImage *images; + VkImageView *imageViews; }; /** Vulkan application that uses Pugl for windows and events */ @@ -110,6 +131,8 @@ struct RenderVulkan { VkDevice device; VkQueue graphicsQueue; VkCommandPool commandPool; + struct SwapchainVulkan swapchain; + VkCommandBuffer *commandBuffers; }; #define RVK_ERRMSG_LEN 4096 @@ -549,6 +572,27 @@ int rvkCreate(PuglWorld *world, struct RenderVulkan **vkOut) return -1; } + static const char *const _vkGetPhysicalDeviceSurfaceCapabilitiesKHR = "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"; + vk->api->vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)vk->api->vkGetInstanceProcAddr(vk->instance, _vkGetPhysicalDeviceSurfaceCapabilitiesKHR); + if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR) { + rvkSetErrMsg(vk, strErrLd, _vkGetPhysicalDeviceSurfaceCapabilitiesKHR); + return -1; + } + + static const char *const _vkGetPhysicalDeviceSurfaceFormatsKHR = "vkGetPhysicalDeviceSurfaceFormatsKHR"; + vk->api->vkGetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)vk->api->vkGetInstanceProcAddr(vk->instance, _vkGetPhysicalDeviceSurfaceFormatsKHR); + if (!vk->api->vkGetPhysicalDeviceSurfaceFormatsKHR) { + rvkSetErrMsg(vk, strErrLd, _vkGetPhysicalDeviceSurfaceFormatsKHR); + return -1; + } + + static const char *const _vkGetPhysicalDeviceSurfacePresentModesKHR = "vkGetPhysicalDeviceSurfacePresentModesKHR"; + vk->api->vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)vk->api->vkGetInstanceProcAddr(vk->instance, _vkGetPhysicalDeviceSurfacePresentModesKHR); + if (!vk->api->vkGetPhysicalDeviceSurfacePresentModesKHR) { + rvkSetErrMsg(vk, strErrLd, _vkGetPhysicalDeviceSurfacePresentModesKHR); + return -1; + } + /* End loading function pointers */ if (vk->api->vkCreateDebugReportCallbackEXT) { @@ -780,6 +824,20 @@ static int rvkLoadDeviceFunctions(struct RenderVulkan *vk, VkDevice device) return -1; } + static const char *const _vkCreateSwapchainKHR = "vkCreateSwapchainKHR"; + vk->dev->vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)vk->api->vkGetDeviceProcAddr(device, _vkCreateSwapchainKHR); + if (!vk->dev->vkCreateSwapchainKHR) { + rvkSetErrMsg(vk, strErrLd, _vkCreateSwapchainKHR); + return -1; + } + + static const char *const _vkDestroySwapchainKHR = "vkDestroySwapchainKHR"; + vk->dev->vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)vk->api->vkGetDeviceProcAddr(device, _vkDestroySwapchainKHR); + if (!vk->dev->vkDestroySwapchainKHR) { + rvkSetErrMsg(vk, strErrLd, _vkDestroySwapchainKHR); + return -1; + } + return 0; } @@ -853,6 +911,170 @@ static void rvkCloseDevice(struct RenderVulkan *vk) vk->device = VK_NULL_HANDLE; } +static int rvkCreateRawSwapchain(struct RenderVulkan *vk, int width, int height) +{ + VkSurfaceCapabilitiesKHR surfaceCapabilities; + VkSurfaceFormatKHR *surfaceFormats; + VkPresentModeKHR *presentModes; // TODO + VkResult result; + if ((result = vk->api->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + vk->physicalDevice, vk->surface, &surfaceCapabilities))) { + rvkSetErrMsg(vk, "Could not get surface capabilities: %d", result); + return -1; + } + uint32_t nFormats; + vk->api->vkGetPhysicalDeviceSurfaceFormatsKHR(vk->physicalDevice, vk->surface, &nFormats, NULL); + if (!nFormats) { + rvkSetErrMsg(vk, "No surface formats available"); + return -1; + } + surfaceFormats = malloc(nFormats * sizeof(*surfaceFormats)); + vk->api->vkGetPhysicalDeviceSurfaceFormatsKHR(vk->physicalDevice, vk->surface, &nFormats, surfaceFormats); + + uint32_t i; + for (i = 0; i < nFormats; ++i) { + const VkSurfaceFormatKHR want = { + VK_FORMAT_B8G8R8A8_SRGB, // BGRA sRGB + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + }; + if (surfaceFormats[i].format == VK_FORMAT_UNDEFINED) { + vk->swapchain.surfaceFormat = want; + break; + } + if (surfaceFormats[i].format == want.format && surfaceFormats[i].colorSpace == want.colorSpace) { + vk->swapchain.surfaceFormat = want; + break; + } + } + free(surfaceFormats); + if (i >= nFormats) { + rvkSetErrMsg(vk, "Could not find a suitable surface format"); + return -1; + } + + // TODO + VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; + + // TODO: Clamp + vk->swapchain.extent.width = width; + vk->swapchain.extent.height = height; + + vk->swapchain.nImages = surfaceCapabilities.minImageCount; + + VkSwapchainCreateInfoKHR createInfo = { 0 }; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = vk->surface; + createInfo.minImageCount = vk->swapchain.nImages; + createInfo.imageFormat = vk->swapchain.surfaceFormat.format; + createInfo.imageExtent = vk->swapchain.extent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.preTransform = surfaceCapabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = VK_NULL_HANDLE; // TODO + if ((result = vk->dev->vkCreateSwapchainKHR(vk->device, &createInfo, ALLOC_VK, &vk->swapchain.rawSwapchain))) { + rvkSetErrMsg(vk, "Could not create swapchain: %d", result); + return -1; + } + return 0; +} + +static void rvkDestroyRawSwapchain(struct RenderVulkan *vk) +{ + vk->dev->vkDestroySwapchainKHR(vk->device, vk->swapchain.rawSwapchain, ALLOC_VK); + memset(&vk->swapchain.surfaceFormat, 0, sizeof(vk->swapchain.surfaceFormat)); + memset(&vk->swapchain, 0, sizeof(vk->swapchain)); +} + +static VkResult createSwapchainImageViews(VkDevice device, + const struct VulkanDev *const dev, struct SwapchainVulkan *const swapchain) +{ + 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)); + + VkResult result; + for (uint32_t i = 0; i < swapchain->nImages; ++i) { + VkImageViewCreateInfo createInfo = { 0 }; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = swapchain->images[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = swapchain->surfaceFormat.format; + createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseMipLevel = 0; + 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; + } + } + return VK_SUCCESS; +} + +static void destroySwapchainImageViews(VkDevice device, + const struct VulkanDev *const dev, struct SwapchainVulkan *const swapchain) +{ + for (uint32_t i = 0; i < swapchain->nImages; ++i) { + dev->vkDestroyImageView(device, swapchain->imageViews[i], ALLOC_VK); + } + free(swapchain->imageViews); + free(swapchain->images); + swapchain->imageViews = NULL; + swapchain->images = NULL; +} + +static VkResult allocateCommandBuffers(struct RenderVulkan *vk) +{ + VkCommandBufferAllocateInfo allocInfo = { 0 }; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = vk->commandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = vk->swapchain.nImages; + vk->commandBuffers = malloc(vk->swapchain.nImages * sizeof(vk->commandBuffers)); + return vk->dev->vkAllocateCommandBuffers(vk->device, &allocInfo, vk->commandBuffers); +} + +static void freeCommandBuffers(struct RenderVulkan *vk) +{ + vk->dev->vkFreeCommandBuffers(vk->device, vk->commandPool, vk->swapchain.nImages, vk->commandBuffers); + free(vk->commandBuffers); + vk->commandBuffers = NULL; +} + +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; + + VkImageSubresourceRange range = { 0 }; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + + 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; + vk->dev->vkBeginCommandBuffer(vk->commandBuffers[i], &beginInfo); + vk->dev->vkCmdClearColorImage(vk->commandBuffers[i], vk->swapchain.images[i], + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, &clearValue, 1, &range); + } +} + /** This must work no matter the current state of `vk` */ void rvkDestroy(struct RenderVulkan *vk) { @@ -860,6 +1082,7 @@ void rvkDestroy(struct RenderVulkan *vk) /* `vk->device` implies `vk->dev` but device functions MAY not be loaded */ if (vk->device) { if (vk->dev->vkDeviceWaitIdle) vk->dev->vkDeviceWaitIdle(vk->device); + rvkDestroyRawSwapchain(vk); rvkCloseDevice(vk); } if (vk->surface) vk->api->vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); @@ -926,6 +1149,7 @@ int main() PuglView *view = puglNewView(world); const PuglRect frame = { 0, 0, 800, 600 }; + puglSetFrame(view, frame); puglSetBackend(view, puglStubBackend()); PuglStatus status; @@ -938,6 +1162,7 @@ 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)); printf("Opened Vulkan Device Successfully\n"); -- cgit v1.2.1