summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Halase <jordan@halase.me>2019-11-01 16:35:33 -0500
committerJordan Halase <jordan@halase.me>2019-11-01 16:35:33 -0500
commit9fbe9c0edb826c65efd204b34264f42dd77fd3d4 (patch)
tree7643966f052e09ea6e1d764a7bb0bbf386d36f15
parenta6662f92f19459f013ec2168d0b7ccbce349f458 (diff)
Add more functionality
-rw-r--r--main.c235
1 files 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");