From 364eea8654a69dd0e79cdfa86c10992e6e275ccd Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Wed, 28 Feb 2018 00:35:15 +0000 Subject: init commit --- vulkan.c | 839 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 839 insertions(+) create mode 100644 vulkan.c (limited to 'vulkan.c') diff --git a/vulkan.c b/vulkan.c new file mode 100644 index 0000000..420be16 --- /dev/null +++ b/vulkan.c @@ -0,0 +1,839 @@ +#include +#include +#include +#include +#include +#include + +#include "eprintf.h" +#include "nelem.h" +#include "shaders.h" +#include "strlist.h" +#include "validation.h" + +#define LIST_REALLOC(l) (l)->list = erealloc((l)->list, (l)->count * sizeof *(l)->list) +#define LIST_FOREACH(l, i) for (uint32_t i = 0; i < (l)->count; i++) + +enum { + WINWIDTH = 800, + WINHEIGHT = 600, +}; +static const char *NAME = "Vulkan Test"; + +enum qfams { + QF_GRAPHICS, + QF_PRESENT, + QF_MAX, +}; + +const char *devexts[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, +}; + +struct swp { + VkSwapchainKHR swp; + struct swpimgs { + VkImage *list; + uint32_t count; + } imgs; + VkFormat format; + VkExtent2D extent; +}; + +struct ppln { + VkPipeline ppln; + VkPipelineLayout layout; +}; + +struct views { + VkImageView *list; + uint32_t count; +}; + +struct fbs { + VkFramebuffer *list; + uint32_t count; +}; + +struct cmdbufs { + VkCommandBuffer *list; + uint32_t count; +}; + +struct swpdtl { + VkSurfaceCapabilitiesKHR caps; + struct swpfmts { + VkSurfaceFormatKHR *list; + uint32_t count; + } fmts; + struct swppmodes { + VkPresentModeKHR *list; + uint32_t count; + } pmodes; +}; + +static GLFWwindow *createwin(int width, int height, const char *title) +{ + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + + return glfwCreateWindow(width, height, title, NULL, NULL); +} + +static void glfwexts(struct strlist *exts) +{ + const char **gexts; + uint32_t ngexts; + + assert(exts != NULL); + + gexts = glfwGetRequiredInstanceExtensions(&ngexts); + sl_append(exts, gexts, ngexts); +} + +static VkInstance createinst(void) +{ + struct strlist layers = { 0 }, exts = { 0 }; + VkInstanceCreateInfo info; + VkInstance inst; + VkResult res; + + glfwexts(&exts); + validation_info(&layers, &exts); + info = (VkInstanceCreateInfo){ + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &(VkApplicationInfo){ + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = NAME, + .applicationVersion = VK_MAKE_VERSION(1, 0, 0), + .pEngineName = NAME, + .engineVersion = VK_MAKE_VERSION(1, 0, 0), + .apiVersion = VK_API_VERSION_1_0, + }, + .enabledExtensionCount = exts.count, + .ppEnabledExtensionNames = exts.list, + .enabledLayerCount = layers.count, + .ppEnabledLayerNames = layers.list, + }; + + + res = vkCreateInstance(&info, NULL, &inst); + if (res != VK_SUCCESS) + eprintf("Could not create instance"); + + sl_free(&layers); + sl_free(&exts); + + return inst; +} + +static bool hasdevexts(VkPhysicalDevice phy) +{ + bool hasext[NELEM(devexts)] = { 0 }; + VkExtensionProperties *extprops; + uint32_t nextprops; + + vkEnumerateDeviceExtensionProperties(phy, NULL, &nextprops, NULL); + extprops = emalloc(nextprops * sizeof *extprops); + vkEnumerateDeviceExtensionProperties(phy, NULL, &nextprops, extprops); + + for (uint32_t pi = 0; pi < nextprops; pi++) { + for (int xi = 0; xi < NELEM(devexts); xi++) { + if (strcmp(devexts[xi], extprops[pi].extensionName) == 0) { + hasext[xi] = true; + break; + } + } + } + + free(extprops); + + for (int i = 0; i < NELEM(hasext); i++) + if (!hasext[i]) + return false; + + return true; +} + +static bool isdevsuitable(VkPhysicalDevice phy, const int *qf, const struct swpdtl *sdtl) +{ + assert(qf != NULL); + + return qf[QF_GRAPHICS] >= 0 && qf[QF_PRESENT] >= 0 && + hasdevexts(phy) && sdtl->fmts.count > 0 && + sdtl->pmodes.count > 0; +} + +static void getdevqfams(int *qf, VkPhysicalDevice phy, VkSurfaceKHR surf) +{ + VkQueueFamilyProperties *qfprops; + uint32_t nqfprops; + + assert(qf != NULL); + + vkGetPhysicalDeviceQueueFamilyProperties(phy, &nqfprops, NULL); + qfprops = emalloc(nqfprops * sizeof *qfprops); + vkGetPhysicalDeviceQueueFamilyProperties(phy, &nqfprops, qfprops); + + for (int i = 0; i < QF_MAX; i++) qf[i] = -1; + + for (uint32_t i = 0; i < nqfprops; i++) { + VkQueueFamilyProperties *qfp = &qfprops[i]; + VkBool32 present = false; + + if (qfp->queueCount <= 0) continue; + if (qf[QF_GRAPHICS] < 0 && qfp->queueFlags & VK_QUEUE_GRAPHICS_BIT) + qf[QF_GRAPHICS] = i; + vkGetPhysicalDeviceSurfaceSupportKHR(phy, i, surf, &present); + if (qf[QF_PRESENT] < 0 && present) qf[QF_PRESENT] = i; + } + + free(qfprops); +} + +static void getswpdtl(struct swpdtl *sdtl, VkPhysicalDevice phy, VkSurfaceKHR surf) +{ + assert(sdtl != NULL); + + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phy, surf, &sdtl->caps); + + vkGetPhysicalDeviceSurfaceFormatsKHR(phy, surf, &sdtl->fmts.count, NULL); + LIST_REALLOC(&sdtl->fmts); + vkGetPhysicalDeviceSurfaceFormatsKHR(phy, surf, &sdtl->fmts.count, sdtl->fmts.list); + + vkGetPhysicalDeviceSurfacePresentModesKHR(phy, surf, &sdtl->pmodes.count, NULL); + LIST_REALLOC(&sdtl->pmodes); + vkGetPhysicalDeviceSurfacePresentModesKHR(phy, surf, &sdtl->pmodes.count, sdtl->pmodes.list); +} +static void freeswpdtl(struct swpdtl *sdtl) +{ + assert(sdtl != NULL); + + free(sdtl->fmts.list); + free(sdtl->pmodes.list); +} + +static VkPhysicalDevice pickphy(int *qf, struct swpdtl *sdtl, VkInstance inst, VkSurfaceKHR surf) +{ + VkPhysicalDevice *phys, phy; + uint32_t nphys; + + assert(qf != NULL); + + vkEnumeratePhysicalDevices(inst, &nphys, NULL); + phys = emalloc(nphys * sizeof *phys); + vkEnumeratePhysicalDevices(inst, &nphys, phys); + + phy = VK_NULL_HANDLE; + + for (uint32_t i = 0; i < nphys; i++) { + getdevqfams(qf, phys[i], surf); + getswpdtl(sdtl, phys[i], surf); + if (isdevsuitable(phys[i], qf, sdtl)) { + phy = phys[i]; + break; + } + } + + if (phy == VK_NULL_HANDLE) + eprintf("No suitable GPU found"); + + free(phys); + + return phy; +} + +static int loaddqcinfs(VkDeviceQueueCreateInfo *dqcinfs, const int *qf, const float *prio) +{ + int ndqcinfs = 0; + + for (int fi = 0; fi < QF_MAX; fi++) { + for (int cii = 0; cii < fi; cii++) + if (dqcinfs[cii].queueFamilyIndex == qf[fi]) + goto next; + dqcinfs[ndqcinfs++] = (VkDeviceQueueCreateInfo){ + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = qf[fi], + .queueCount = 1, + .pQueuePriorities = prio, + }; + next: ; + } + + return ndqcinfs; +} + +static VkDevice createdev(VkPhysicalDevice phy, const int *qf) +{ + VkDeviceQueueCreateInfo dqcinfs[QF_MAX]; + struct strlist layers = { 0 }; + VkDeviceCreateInfo info; + uint32_t ndqcinfs; + VkDevice dev; + VkResult res; + + ndqcinfs = loaddqcinfs(dqcinfs, qf, &(float){ 1 }); + validation_info(&layers, NULL); + info = (VkDeviceCreateInfo){ + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pQueueCreateInfos = dqcinfs, + .queueCreateInfoCount = ndqcinfs, + .pEnabledFeatures = &(VkPhysicalDeviceFeatures){ 0 }, + .enabledLayerCount = layers.count, + .ppEnabledLayerNames = layers.list, + .enabledExtensionCount = 1, + .ppEnabledExtensionNames = devexts, + }; + res = vkCreateDevice(phy, &info, NULL, &dev); + if (res != VK_SUCCESS) + eprintf("Could not create device"); + + return dev; +} + +static VkSurfaceFormatKHR getswpfmt(struct swpfmts *scf) +{ + assert(scf != NULL); + + if (scf->count == 1 && scf->list[0].format == VK_FORMAT_UNDEFINED) + return (VkSurfaceFormatKHR){ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; + + for (uint32_t i = 0; i < scf->count; i++) + if (scf->list[i].format == VK_FORMAT_B8G8R8A8_UNORM + && scf->list[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + return scf->list[i]; + + return scf->list[0]; +} + +static VkPresentModeKHR getswppmode(struct swppmodes *scp) +{ + VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; + + assert(scp != NULL); + + for (uint32_t i = 0; i < scp->count; i++) { + if (scp->list[i] == VK_PRESENT_MODE_MAILBOX_KHR) + return scp->list[i]; + if (scp->list[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) + mode = scp->list[i]; + } + + return mode; +} + +static VkExtent2D getswpextent(const VkSurfaceCapabilitiesKHR *caps) +{ + VkExtent2D extent = { WINWIDTH, WINHEIGHT }; + + if (caps->currentExtent.width != UINT32_MAX) + return caps->currentExtent; + + if (extent.width > caps->maxImageExtent.width) extent.width = caps->maxImageExtent.width; + if (extent.width < caps->minImageExtent.width) extent.width = caps->minImageExtent.width; + + if (extent.height > caps->maxImageExtent.height) extent.height = caps->maxImageExtent.height; + if (extent.height < caps->minImageExtent.height) extent.height = caps->minImageExtent.height; + + return extent; +} + +static void createswp(struct swp *swp, VkSurfaceKHR surf, VkDevice dev, const int *qf, struct swpdtl *sdtl) +{ + VkSwapchainCreateInfoKHR info; + VkPresentModeKHR pmode; + VkSurfaceFormatKHR fmt; + uint32_t qfi[QF_MAX]; + VkResult res; + + assert(swp != NULL); + assert(qf != NULL); + assert(sdtl != NULL); + + fmt = getswpfmt(&sdtl->fmts); + pmode = getswppmode(&sdtl->pmodes); + swp->extent = getswpextent(&sdtl->caps); + swp->imgs.count = sdtl->caps.minImageCount + 1; + if (sdtl->caps.maxImageCount != 0 && swp->imgs.count > sdtl->caps.maxImageCount) + swp->imgs.count = sdtl->caps.maxImageCount; + + for (int i = 0; i < QF_MAX; i++) qfi[i] = qf[i]; + + info = (VkSwapchainCreateInfoKHR){ + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .surface = surf, + .minImageCount = swp->imgs.count, + .imageFormat = fmt.format, + .imageColorSpace = fmt.colorSpace, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .imageSharingMode = qf[QF_GRAPHICS] == qf[QF_PRESENT] + ? VK_SHARING_MODE_EXCLUSIVE + : VK_SHARING_MODE_CONCURRENT, + .queueFamilyIndexCount = QF_MAX, + .pQueueFamilyIndices = qfi, + .preTransform = sdtl->caps.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = pmode, + .clipped = VK_TRUE, + .oldSwapchain = VK_NULL_HANDLE, + }; + + res = vkCreateSwapchainKHR(dev, &info, NULL, &swp->swp); + if (res != VK_SUCCESS) + eprintf("Could not create swapchain"); + + swp->imgs = (struct swpimgs){ 0 }; + vkGetSwapchainImagesKHR(dev, swp->swp, &swp->imgs.count, NULL); + LIST_REALLOC(&swp->imgs); + vkGetSwapchainImagesKHR(dev, swp->swp, &swp->imgs.count, swp->imgs.list); +} + +static void createviews(struct views *views, VkDevice dev, const struct swpimgs *imgs, VkFormat fmt) +{ + VkImageViewCreateInfo info; + VkResult res; + + assert(views != NULL); + assert(imgs != NULL); + + *views = (struct views){ .count = imgs->count }; + LIST_REALLOC(views); + + LIST_FOREACH(views, i) { + info = (VkImageViewCreateInfo){ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = imgs->list[i], + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = fmt, + .components = { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + res = vkCreateImageView(dev, &info, NULL, &views->list[i]); + if (res != VK_SUCCESS) + eprintf("Could not create image view"); + } +} + +static void destroyviews(struct views *views, VkDevice dev) +{ + LIST_FOREACH(views, i) vkDestroyImageView(dev, views->list[i], NULL); +} + +static VkShaderModule createsmod(VkDevice dev, const void *data, size_t size) +{ + VkShaderModuleCreateInfo smcinf; + VkShaderModule smod; + VkResult res; + + assert(data != NULL); + + smcinf = (VkShaderModuleCreateInfo){ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = size, + .pCode = data, + }; + + res = vkCreateShaderModule(dev, &smcinf, NULL, &smod); + if (res != VK_SUCCESS) + eprintf("Could not create shader module"); + + return smod; +} + +static VkRenderPass createpass(VkDevice dev, VkFormat fmt) +{ + VkRenderPassCreateInfo info; + VkRenderPass pass; + VkResult res; + + info = (VkRenderPassCreateInfo){ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &(VkAttachmentDescription){ + .format = fmt, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + }, + .subpassCount = 1, + .pSubpasses = &(VkSubpassDescription){ + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &(VkAttachmentReference){ + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }, + }, + .dependencyCount = 1, + .pDependencies = &(VkSubpassDependency){ + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = 0, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + }, + }; + + res = vkCreateRenderPass(dev, &info, NULL, &pass); + if (res != VK_SUCCESS) + eprintf("Could not create render pass"); + + return pass; +} + +static void createpipeline(struct ppln *ppln, VkDevice dev, const VkExtent2D *extent) +{ + VkGraphicsPipelineCreateInfo gpcinf; + VkPipelineLayoutCreateInfo plcinf; + VkShaderModule fsmod, vsmod; + VkResult res; + + assert(ppln != NULL); + assert(extent != NULL); + + plcinf = (VkPipelineLayoutCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + /* .setLayoutCount = 0, */ + /* .pSetLayouts = NULL, */ + /* .pushConstantRangeCount = 0, */ + /* .pPushConstantRanges = 0, */ + }; + + res = vkCreatePipelineLayout(dev, &plcinf, NULL, &ppln->layout); + if (res != VK_SUCCESS) + eprintf("Could not create pipeline layout"); + + vsmod = createsmod(dev, _binary_vertex_spv_start, _binary_vertex_spv_size); + fsmod = createsmod(dev, _binary_fragment_spv_start, _binary_fragment_spv_size); + + gpcinf = (VkGraphicsPipelineCreateInfo){ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 2, + .pStages = (VkPipelineShaderStageCreateInfo []){ + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = vsmod, + .pName = "main", + }, { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = fsmod, + .pName = "main", + }, + }, + .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 0, + .pVertexBindingDescriptions = NULL, + .vertexAttributeDescriptionCount = 0, + .pVertexAttributeDescriptions = NULL, + }, + .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE, + }, + .pViewportState = &(VkPipelineViewportStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .pViewports = &(VkViewport){ + .x = 0.0f, + .y = 0.0f, + .width = (float)extent->width, + .height = (float)extent->height, + .minDepth = 0.0f, + .maxDepth = 1.0f, + }, + .scissorCount = 1, + .pScissors = &(VkRect2D){ + .offset = { 0, 0 }, + .extent = *extent, + }, + }, + .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .lineWidth = 1.0f, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .depthBiasEnable = VK_FALSE, + /* .depthBiasConstantFactor = 0, */ + /* .depthBiasClamp = 0, */ + /* .depthBiasSlopeFactor = 0, */ + }, + .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .sampleShadingEnable = VK_FALSE, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + /* .minSampleShading = 1, */ + /* .pSampleMask = NULL, */ + /* .alphaToCoverageEnable = VK_FALSE, */ + /* .alphaToOneEnable = VK_FALSE, */ + }, + .pDepthStencilState = NULL, + .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .logicOpEnable = VK_FALSE, + /* .logicOp = VK_LOGIC_OP_COPY, */ + .attachmentCount = 1, + .pAttachments = &(VkPipelineColorBlendAttachmentState){ + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + .blendEnable = VK_FALSE, + /* .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, */ + /* .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, */ + /* .colorBlendOp = VK_BLEND_OP_ADD, */ + /* .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, */ + /* .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, */ + /* .alphaBlendOp = VK_BLEND_OP_ADD, */ + }, + /* .blendConstants[0] = 0, */ + /* .blendConstants[1] = 0, */ + /* .blendConstants[2] = 0, */ + /* .blendConstants[3] = 0, */ + }, + .pDynamicState = NULL, + }; + + res = vkCreateGraphicsPipelines(dev, VK_NULL_HANDLE, 1, &gpcinf, NULL, &ppln->ppln); + if (res != VK_SUCCESS) + eprintf("Could not create graphics pipeline"); + + vkDestroyShaderModule(dev, fsmod, NULL); + vkDestroyShaderModule(dev, vsmod, NULL); +} + +static void destroyppln(struct ppln *ppln, VkDevice dev) +{ + vkDestroyPipeline(dev, ppln->ppln, NULL); + vkDestroyPipelineLayout(dev, ppln->layout, NULL); +} + +static void createfbs(struct fbs *fbs, VkDevice dev, const struct views *views, VkRenderPass pass, const VkExtent2D *extent) +{ + VkFramebufferCreateInfo info; + VkResult res; + + assert(fbs != NULL); + assert(views != NULL); + + *fbs = (struct fbs){ .count = views->count }; + LIST_REALLOC(fbs); + + LIST_FOREACH(fbs, i) { + info = (VkFramebufferCreateInfo){ + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = pass, + .attachmentCount = 1, + .pAttachments = &views->list[i], + .width = extent->width, + .height = extent->height, + .layers = 1, + }; + res = vkCreateFramebuffer(dev, &info, NULL, &fbs->list[i]); + if (res != VK_SUCCESS) + eprintf("Could not create framebuffer"); + } +} + +static void destroyfbs(struct fbs *fbs, VkDevice dev) +{ + LIST_FOREACH(fbs, i) vkDestroyFramebuffer(dev, fbs->list[i], NULL); +} + +static VkCommandPool createcpool(struct cmdbufs *cmdbufs, VkDevice dev, const int *qf, + const struct fbs *fbs, VkRenderPass pass, + VkExtent2D *extent, const struct ppln *ppln) +{ + VkCommandBufferAllocateInfo cbainf; + VkCommandPoolCreateInfo cpcinf; + VkCommandPool cpool; + VkResult res; + + assert(cmdbufs != NULL); + assert(qf != NULL); + + cpcinf = (VkCommandPoolCreateInfo){ + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .queueFamilyIndex = qf[QF_GRAPHICS], + }; + + res = vkCreateCommandPool(dev, &cpcinf, NULL, &cpool); + if (res != VK_SUCCESS) + eprintf("Could not create command pool"); + + *cmdbufs = (struct cmdbufs){ .count = fbs->count }; + LIST_REALLOC(cmdbufs); + cbainf = (VkCommandBufferAllocateInfo){ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = cpool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = fbs->count, + }; + res = vkAllocateCommandBuffers(dev, &cbainf, cmdbufs->list); + if (res != VK_SUCCESS) + eprintf("Could not create command buffers"); + + LIST_FOREACH(cmdbufs, i) { + vkBeginCommandBuffer(cmdbufs->list[i], &(VkCommandBufferBeginInfo){ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, + /* .pInheritanceInfo = NULL, */ + }); + vkCmdBeginRenderPass(cmdbufs->list[i], &(VkRenderPassBeginInfo){ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = pass, + .framebuffer = fbs->list[i], + .renderArea.offset = {0, 0}, + .renderArea.extent = *extent, + .clearValueCount = 1, + .pClearValues = &(VkClearValue){ + .color = { + .float32 = { 0, 0, 0, 1 } + } + }, + }, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(cmdbufs->list[i], VK_PIPELINE_BIND_POINT_GRAPHICS, ppln->ppln); + vkCmdDraw(cmdbufs->list[i], 3, 1, 0, 0); + vkCmdEndRenderPass(cmdbufs->list[i]); + }; + + return cpool; +} + +static VkSemaphore createsem(VkDevice dev) +{ + VkSemaphore sem; + VkResult res; + + res = vkCreateSemaphore(dev, &(VkSemaphoreCreateInfo){ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + }, NULL, &sem); + if (res != VK_SUCCESS) + eprintf("Could not create semaphore"); + + return sem; +} + +void drawframe(VkDevice dev, VkSwapchainKHR swp, VkQueue graphq, + VkQueue presq, VkSemaphore semavail, + VkSemaphore semfin, const struct cmdbufs *cmdbufs) +{ + VkPresentInfoKHR pinf; + VkSubmitInfo sinf; + uint32_t i; + + vkAcquireNextImageKHR(dev, swp, UINT64_MAX, semavail, VK_NULL_HANDLE, &i); + sinf = (VkSubmitInfo){ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &semavail, + .pWaitDstStageMask = &(VkPipelineStageFlags){ + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + }, + .commandBufferCount = 1, + .pCommandBuffers = &cmdbufs->list[i], + .signalSemaphoreCount = 1, + .pSignalSemaphores = &semfin, + }; + vkQueueSubmit(graphq, 1, &sinf, VK_NULL_HANDLE); + + pinf = (VkPresentInfoKHR){ + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &semfin, + .swapchainCount = 1, + .pSwapchains = &swp, + .pImageIndices = &i, + /* .pResults = NULL, */ + }; + + vkQueuePresentKHR(presq, &pinf); +} + +int main(void) +{ + struct cmdbufs cmdbufs = { 0 }; + VkSemaphore semavail, semfin; + struct swpdtl sdtl = { 0 }; + struct ppln ppln = { 0 }; + struct fbs fbs = { 0 }; + VkQueue graphq, presq; + VkPhysicalDevice phy; + VkCommandPool cpool; + struct views views; + VkRenderPass pass; + VkSurfaceKHR surf; + GLFWwindow *win; + VkInstance inst; + int qf[QF_MAX]; + struct swp swp; + VkDevice dev; + VkResult res; + void *cb; + + setprogname("vulkan"); + + glfwInit(); + win = createwin(WINWIDTH, WINHEIGHT, NAME); + inst = createinst(); + cb = validation_createcb(inst); + res = glfwCreateWindowSurface(inst, win, NULL, &surf); + if (res != VK_SUCCESS) + eprintf("Could not create window surface"); + phy = pickphy(qf, &sdtl, inst, surf); + dev = createdev(phy, qf); + vkGetDeviceQueue(dev, qf[QF_GRAPHICS], 0, &graphq); + vkGetDeviceQueue(dev, qf[QF_PRESENT], 0, &presq); + createswp(&swp, surf, dev, qf, &sdtl); + createviews(&views, dev, &swp.imgs, swp.format); + pass = createpass(dev, swp.format); + createpipeline(&ppln, dev, &swp.extent); + createfbs(&fbs, dev, &views, pass, &swp.extent); + cpool = createcpool(&cmdbufs, dev, qf, &fbs, pass, &swp.extent, &ppln); + semavail = createsem(dev); + semfin = createsem(dev); + + while (!glfwWindowShouldClose(win)) { + glfwPollEvents(); + drawframe(dev, swp.swp, graphq, presq, semavail, semfin, &cmdbufs); + } + + vkDeviceWaitIdle(dev); + + vkDestroySemaphore(dev, semfin, NULL); + vkDestroySemaphore(dev, semavail, NULL); + vkDestroyCommandPool(dev, cpool, NULL); + destroyfbs(&fbs, dev); + destroyppln(&ppln, dev); + vkDestroyRenderPass(dev, pass, NULL); + destroyviews(&views, dev); + free(views.list); + vkDestroySwapchainKHR(dev, swp.swp, NULL); + vkDestroySurfaceKHR(inst, surf, NULL); + vkDestroyDevice(dev, NULL); + freeswpdtl(&sdtl); + validation_destroycb(inst, cb); + vkDestroyInstance(inst, NULL); + glfwDestroyWindow(win); + glfwTerminate(); +} -- cgit v1.2.3-54-g00ecf