diff --git a/src/main.c b/src/main.c index 799261e..6c9eda7 100644 --- a/src/main.c +++ b/src/main.c @@ -2,13 +2,14 @@ #include #include #include +#include #include "debug.h" #include "render_context.h" #define APPNAME "VulkanApp" -const char* appName = APPNAME; -const VkApplicationInfo appInfo = { +static const char *appName = APPNAME; +static const VkApplicationInfo appInfo = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = APPNAME, .applicationVersion = VK_MAKE_VERSION(0, 0, 1), @@ -17,6 +18,79 @@ const VkApplicationInfo appInfo = { .apiVersion = VK_API_VERSION_1_0, }; +static void RecordCommandBuffer(RenderContext *context, VkCommandBuffer buffer, uint32_t imageIndex) { + VkCommandBufferBeginInfo bufferBegin = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + if(vkBeginCommandBuffer(context->commandBuffer, &bufferBegin) != VK_SUCCESS) { + RETURN_ERROR(,"Failed to start command buffer"); + } + + VkClearValue clearColor = {.color={.float32 = {0.f, 0.f, 0.f, 1.0f}}}; + VkRenderPassBeginInfo passBegin = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = context->renderPass, + .framebuffer = *list_at_as(VkFramebuffer, &context->swapchainBuffers, imageIndex), + .renderArea = { + .offset = {0,0}, + .extent = context->swapchainExtent + }, + .clearValueCount = 1, + .pClearValues = &clearColor, + }; + vkCmdBeginRenderPass(context->commandBuffer, &passBegin, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(context->commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, context->graphicsPipeline); + VkViewport viewport = { + .x = 0.f, .y = 0.f, + .width = context->swapchainExtent.width, + .height = context->swapchainExtent.height, + .minDepth = 0.f, + .maxDepth = 1.f, + }; + vkCmdSetViewport(context->commandBuffer, 0, 1, &viewport); + VkRect2D scissor = { + .offset = {0,0}, + .extent = context->swapchainExtent + }; + vkCmdSetScissor(context->commandBuffer, 0, 1, &scissor); + vkCmdDraw(context->commandBuffer, 3, 1, 0, 0); + vkCmdEndRenderPass(context->commandBuffer); + if(vkEndCommandBuffer(context->commandBuffer) != VK_SUCCESS) { + RETURN_ERROR(, "Failed to finish command recording"); + } +} + +static void Draw(RenderContext *context) { + vkWaitForFences(context->device, 1, &context->inFlight, VK_TRUE, UINT64_MAX); + vkResetFences(context->device, 1, &context->inFlight); + vkResetCommandBuffer(context->commandBuffer, 0); + uint32_t imageIndex = 0; + vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->imageAvailable, VK_NULL_HANDLE, &imageIndex); + RecordCommandBuffer(context, context->commandBuffer, imageIndex); + VkSemaphore waits[] = { context->imageAvailable }; + VkPipelineStageFlags stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + VkSemaphore signals[] = { context->renderFinished }; + VkSubmitInfo submit = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 1, + .pWaitSemaphores = waits, + .pWaitDstStageMask = stages, + .commandBufferCount = 1, + .pCommandBuffers = &context->commandBuffer, + .signalSemaphoreCount = 1, + .pSignalSemaphores = signals, + }; + if(vkQueueSubmit(context->graphicsQueue, 1, &submit, context->inFlight) != VK_SUCCESS) { + RETURN_ERROR(, "Failed to submit graphics queue to GPU"); + } + VkPresentInfoKHR present = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = 1, + .pWaitSemaphores = signals, + .swapchainCount = 1, + .pSwapchains = &context->swapchain, + .pImageIndices = &imageIndex + }; + vkQueuePresentKHR(context->graphicsQueue, &present); +} void Quit(RenderContext *context) { RenderContextDestroy(context); @@ -26,11 +100,12 @@ void Quit(RenderContext *context) { void Loop(RenderContext *context) { SDL_Event event; - while(1) { + do { SDL_PollEvent(&event); - if(event.type == SDL_QUIT) - Quit(context); - } + Draw(context); + } while(event.type != SDL_QUIT); + vkDeviceWaitIdle(context->device); + Quit(context); } int main(int argc, char* argv[]) { diff --git a/src/render_context.c b/src/render_context.c index aa58d17..77ab9e8 100644 --- a/src/render_context.c +++ b/src/render_context.c @@ -1,6 +1,7 @@ #include "render_context.h" #include #include +#include #include #include "debug.h" #include "list.h" @@ -15,6 +16,20 @@ static const List requiredVulkanExtensions = { .element_size = sizeof(char*) }; +static List LoadFileBytes(const char* filename) { + FILE* file = fopen(filename, "rb"); + ASSERT_RETURN(file != NULL, (List){0}, "Failed to load file %s", filename); + fseek(file, 0, SEEK_END); + long len = ftell(file)+1; + List buffer = list_with_len(sizeof(char), len-1); + fseek(file, 0, SEEK_SET); + fread(buffer.data, sizeof(char), len, file); + ASSERT_RETURN(feof(file), buffer, "Did not read to end of file while loading data from %s", filename); + ASSERT_RETURN(!ferror(file), buffer, "Encountered file error while loading data from %s", filename); + fclose(file); + return buffer; +} + // get the list of supported vulkan protocol extensions static List RenderContextGetExtensions(const RenderContext *self) { // get the number of available extensions @@ -62,7 +77,7 @@ static VkExtent2D SelectSwapExtent(RenderContext *self, const VkSurfaceCapabilit return (VkExtent2D) { .width = CLAMP((uint32_t)width, capabilities->minImageExtent.width, capabilities->maxImageExtent.width), .height = CLAMP((uint32_t)height, capabilities->minImageExtent.height, capabilities->maxImageExtent.height) - };; + }; } static int CheckExtensionSupport(VkPhysicalDevice device) { @@ -132,7 +147,7 @@ static void RenderContextInitSdlWindow(RenderContext* self, const VkApplicationI 1920, 1080, SDL_WINDOW_VULKAN | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_SHOWN); if(!self->window) { - LOG_ERROR("Failed to create window: %s", SDL_GetError()); + RETURN_ERROR(,"Failed to create window: %s", SDL_GetError()); } } @@ -140,14 +155,19 @@ static void RenderContextInitSdlWindow(RenderContext* self, const VkApplicationI // initializes self->vulkanInstance static void RenderContextInitVulkanInstance(RenderContext *self, const VkApplicationInfo *appinfo) { List extensions = RenderContextGetExtensions(self); + const char* validationLayers[] = { + "VK_LAYER_KHRONOS_validation" + }; VkInstanceCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = appinfo, .enabledExtensionCount = extensions.len, .ppEnabledExtensionNames = extensions.data, + .enabledLayerCount = 1, + .ppEnabledLayerNames = validationLayers }; if(vkCreateInstance(&createInfo, NULL, &self->vulkanInstance) != VK_SUCCESS) { - LOG_ERROR("Failed to initialize vulkan instance"); + RETURN_ERROR(,"Failed to initialize vulkan instance"); } list_empty(&extensions); } @@ -208,13 +228,16 @@ static QueueFamilyIndexes RenderContextFindQueueFamilies(RenderContext *self) { static List QueueCreateInfoListFrom(QueueFamilyIndexes indexes) { // return empty list if indexes is not initialized if(!indexes.init) - return list_from_type(VkDeviceQueueCreateInfo); + RETURN_ERROR(list_from_type(VkDeviceQueueCreateInfo), "Failed to init queue family indeces"); // filter duplicates from indexes List uniqueFamilies = list_from_type(uint32_t); for(size_t i = 0; i < QueueFamilyIndexes_Count; ++i) { - if(!list_contains(&uniqueFamilies, indexes.as_array + i)) { + int isUnique = 1; + list_foreach(uint32_t *, family, &uniqueFamilies) + if((*family) == indexes.as_array[i]) + isUnique = 0; + if(isUnique) list_add(&uniqueFamilies, indexes.as_array + i); - } } // compose list of create infos without priories assigned List createInfo_ = list_from_type_with_len(VkDeviceQueueCreateInfo, uniqueFamilies.len); @@ -224,7 +247,7 @@ static List QueueCreateInfoListFrom(QueueFamilyIndexes indexes) { for(size_t i = 0; i < uniqueFamilies.len; ++i) { createInfo[i] = (VkDeviceQueueCreateInfo) { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = families[0], + .queueFamilyIndex = families[i], .queueCount = 1, }; } @@ -244,14 +267,14 @@ static void RenderContextCreateLogicalDevice(RenderContext *self) { List extensions = list_copy(&requiredVulkanExtensions); VkDeviceCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .queueCreateInfoCount = (uint32_t)queueCreateInfo.len, .pQueueCreateInfos = queueCreateInfo.data, - .queueCreateInfoCount = queueCreateInfo.len, .enabledExtensionCount = (uint32_t)extensions.len, .ppEnabledExtensionNames = extensions.data }; VkPhysicalDeviceFeatures features = {0}; if(vkCreateDevice(self->physicalDevice, &createInfo, NULL, &self->device) != VK_SUCCESS) { - LOG_ERROR("Failed to create vulkan logical device"); + RETURN_ERROR(,"Failed to create vulkan logical device"); } list_empty(&extensions); list_empty(&queueCreateInfo); @@ -261,7 +284,7 @@ static void RenderContextCreateLogicalDevice(RenderContext *self) { static void RenderContextCreateSurface(RenderContext *self) { if(SDL_Vulkan_CreateSurface(self->window, self->vulkanInstance, &self->windowSurface) == SDL_FALSE) { - LOG_ERROR("Failed to create vulkan surface"); + RETURN_ERROR(,"Failed to create vulkan surface"); } } @@ -301,15 +324,277 @@ static void RenderContextCreateSwapchain(RenderContext *self) { } SwapChainSupportInfoClean(&support); if(vkCreateSwapchainKHR(self->device, &createInfo, NULL, &self->swapchain) != VK_SUCCESS) { - LOG_ERROR("Failed to create vulkan swapchain"); + RETURN_ERROR(,"Failed to create vulkan swapchain"); } vkGetSwapchainImagesKHR(self->device, self->swapchain, &chainLength, NULL); self->swapchainImages = list_with_len(sizeof(VkImage), chainLength); vkGetSwapchainImagesKHR(self->device, self->swapchain, &chainLength, self->swapchainImages.data); } +static void RenderContextMakeImageViews(RenderContext *self) { + self->swapchainViews = list_from_type(VkImageView); + list_reserve(&self->swapchainViews, self->swapchainImages.len); + VkImageViewCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = self->swapchainFormat, + .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, + }, + }; + VkImageView createdView; + list_foreach(VkImage *,image, &self->swapchainImages) { + createInfo.image = *image; + if(vkCreateImageView(self->device, &createInfo, NULL, &createdView) != VK_SUCCESS) + RETURN_ERROR(,"Failed to create view for swapchain image"); + else + list_add(&self->swapchainViews, &createdView); + } +} + +static VkShaderModule RenderContextCreateShaderModule(RenderContext *self, const uint32_t* data, uint32_t size) { + VkShaderModuleCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = size, + .pCode = data, + }; + VkShaderModule module; + if(vkCreateShaderModule(self->device, &createInfo, NULL, &module) != VK_SUCCESS) { + RETURN_ERROR(VK_NULL_HANDLE,"Failed to create shader module"); + } + return module; +} + +static VkShaderModule RenderContextShaderModuleFromFile(RenderContext *self, const char* file) { + List data = LoadFileBytes(file); + VkShaderModule mod = RenderContextCreateShaderModule(self, data.data, data.len); + list_empty(&data); + return mod; +} + +static void RenderContextCreateRenderPass(RenderContext *self) { + VkAttachmentDescription attach = { + .format = self->swapchainFormat, + .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, + }; + VkAttachmentReference attachReference = { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; + VkSubpassDescription subpass = { + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &attachReference, + }; + VkSubpassDependency deps = { + .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, + }; + VkRenderPassCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &attach, + .subpassCount = 1, + .pSubpasses = &subpass, + .dependencyCount = 1, + .pDependencies = &deps, + }; + if(vkCreateRenderPass(self->device, &createInfo, NULL, &self->renderPass) != VK_SUCCESS) { + RETURN_ERROR(,"Failed to create vulkan render pass"); + } +} + +static void RenderContextCreateGraphicsPipeline(RenderContext *self) { + self->fragmentShader = RenderContextShaderModuleFromFile(self, "shaders/frag.spv"); + self->vertexShader = RenderContextShaderModuleFromFile(self, "shaders/vert.spv"); + + VkPipelineShaderStageCreateInfo stageCreateInfos[] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = self->vertexShader, + .pName = "main" + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = self->fragmentShader, + .pName = "main" + } + }; + VkPipelineVertexInputStateCreateInfo vertexInput = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 0, + .vertexAttributeDescriptionCount = 0 + }; + VkPipelineInputAssemblyStateCreateInfo assembly = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE, + }; + VkViewport viewport = { + .x = 0.f, .y = 0.f, + .width = (float)self->swapchainExtent.width, + .height = (float)self->swapchainExtent.height, + .minDepth = 0.f, + .maxDepth = 1.f, + }; + VkRect2D scissorRect = { + .offset = {0,0}, + .extent = self->swapchainExtent, + }; + VkDynamicState dynStates[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + VkPipelineDynamicStateCreateInfo dynamicState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = 2, + .pDynamicStates = dynStates, + }; + VkPipelineViewportStateCreateInfo viewportState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .pViewports = &viewport, + .scissorCount = 1, + .pScissors = &scissorRect, + }; + VkPipelineRasterizationStateCreateInfo rasterizer = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .rasterizerDiscardEnable = VK_FALSE, + .lineWidth = 1.0 + }; + VkPipelineMultisampleStateCreateInfo multisample = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .sampleShadingEnable = VK_FALSE, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + }; + VkPipelineColorBlendAttachmentState blendAttachment = { + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + // .blendEnable = VK_FALSE, + .blendEnable = VK_TRUE, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_DST_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .alphaBlendOp = VK_BLEND_OP_ADD, + }; + VkPipelineColorBlendStateCreateInfo blendStateCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .logicOpEnable = VK_FALSE, + .attachmentCount = 1, + .pAttachments = &blendAttachment, + .blendConstants = { 0.f, 0.f, 0.f, 0.f }, + }; + VkPipelineLayoutCreateInfo layoutCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + }; + if(vkCreatePipelineLayout(self->device, &layoutCreateInfo, NULL, &self->pipelineLayout) != VK_SUCCESS) { + RETURN_ERROR(,"Failed to create vulkan pipeline layout"); + } + VkGraphicsPipelineCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 2, + .pStages = stageCreateInfos, + .pVertexInputState = &vertexInput, + .pInputAssemblyState = &assembly, + .pViewportState = &viewportState, + .pRasterizationState = &rasterizer, + .pMultisampleState = &multisample, + .pDepthStencilState = NULL, + .pColorBlendState = &blendStateCreateInfo, + .pDynamicState = &dynamicState, + .layout = self->pipelineLayout, + .renderPass = self->renderPass, + .subpass = 0, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = -1, + }; + if(vkCreateGraphicsPipelines(self->device, VK_NULL_HANDLE, 1, &createInfo, NULL, &self->graphicsPipeline) != VK_SUCCESS) { + RETURN_ERROR(,"Failed to create graphics pipeline"); + } +} + +static void RenderContextCreateFramebuffers(RenderContext *self) { + self->swapchainBuffers = list_with_len(sizeof(VkFramebuffer), self->swapchainViews.len); + VkImageView* views = self->swapchainViews.data; + for(size_t i = 0; i < self->swapchainViews.len; ++i) { + VkFramebufferCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = self->renderPass, + .attachmentCount = 1, + .pAttachments = views + i, + .width = self->swapchainExtent.width, + .height = self->swapchainExtent.height, + .layers = 1 + }; + if(vkCreateFramebuffer(self->device, &createInfo, NULL, list_at(&self->swapchainBuffers, i)) != VK_SUCCESS) { + RETURN_ERROR(,"Failed to create frambuffer %zu", i); + } + } +} + +void RenderContextSetupCommands(RenderContext *self) { + QueueFamilyIndexes indexes = RenderContextFindQueueFamilies(self); + VkCommandPoolCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .queueFamilyIndex = indexes.graphicsQueue, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + }; + if(vkCreateCommandPool(self->device, &createInfo, NULL, &self->commandPool) != VK_SUCCESS) { + RETURN_ERROR(,"Failed to create command pool"); + } + VkCommandBufferAllocateInfo allocInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = self->commandPool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + if(vkAllocateCommandBuffers(self->device, &allocInfo, &self->commandBuffer) != VK_SUCCESS) { + RETURN_ERROR(,"Failed to allocate command buffers"); + } +} + +static void RenderContextCreateSyncObjects(RenderContext *self) { + VkSemaphoreCreateInfo semaphoreInfo = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + VkFenceCreateInfo fenceInfo = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = VK_FENCE_CREATE_SIGNALED_BIT, + }; + if(vkCreateSemaphore(self->device, &semaphoreInfo, NULL, &self->imageAvailable) != VK_SUCCESS + || vkCreateSemaphore(self->device, &semaphoreInfo, NULL, &self->renderFinished) != VK_SUCCESS + || vkCreateFence(self->device, &fenceInfo, NULL, &self->inFlight) != VK_SUCCESS) { + RETURN_ERROR(, "Failed to create synchronisation objects"); + } +} + RenderContext *RenderContextCreate(const VkApplicationInfo *appinfo) { - LOG_INFO("Creating render context"); + LOG_INFO("Allocating render context"); RenderContext* self = malloc(sizeof(RenderContext)); memset(self, 0x0, sizeof(RenderContext)); LOG_INFO("Initializing SDL window"); @@ -322,13 +607,39 @@ RenderContext *RenderContextCreate(const VkApplicationInfo *appinfo) { RenderContextSelectPhysicalDevice(self); LOG_INFO("Creating logical device"); RenderContextCreateLogicalDevice(self); - LOG_INFO("Set up swapchain"); + LOG_INFO("Creating swapchain"); RenderContextCreateSwapchain(self); + LOG_INFO("Creating image views"); + RenderContextMakeImageViews(self); + LOG_INFO("Creating render pass"); + RenderContextCreateRenderPass(self); + LOG_INFO("Creating graphics pipeline"); + RenderContextCreateGraphicsPipeline(self); + LOG_INFO("Creating framebuffers"); + RenderContextCreateFramebuffers(self); + LOG_INFO("Creating command pool"); + RenderContextSetupCommands(self); + LOG_INFO("Creating synchronisation objects"); + RenderContextCreateSyncObjects(self); LOG_INFO("Finished setting up vulkan render context"); return self; } void RenderContextDestroy(RenderContext *self) { + vkDestroyFence(self->device, self->inFlight, NULL); + vkDestroySemaphore(self->device, self->imageAvailable, NULL); + vkDestroySemaphore(self->device, self->renderFinished, NULL); + vkFreeCommandBuffers(self->device, self->commandPool, 1, &self->commandBuffer); + vkDestroyCommandPool(self->device, self->commandPool, NULL); + list_foreach(VkFramebuffer *,buffer, &self->swapchainBuffers) + vkDestroyFramebuffer(self->device, *buffer, NULL); + vkDestroyPipeline(self->device, self->graphicsPipeline, NULL); + vkDestroyPipelineLayout(self->device, self->pipelineLayout, NULL); + vkDestroyRenderPass(self->device, self->renderPass, NULL); + vkDestroyShaderModule(self->device, self->vertexShader, NULL); + vkDestroyShaderModule(self->device, self->fragmentShader, NULL); + list_foreach(VkImageView *,view, &self->swapchainViews) + vkDestroyImageView(self->device, *view, NULL); vkDestroySwapchainKHR(self->device, self->swapchain, NULL); vkDestroySurfaceKHR(self->vulkanInstance, self->windowSurface, NULL); vkDestroyDevice(self->device, NULL); diff --git a/src/render_context.h b/src/render_context.h index 3cca4ea..dfd26c3 100644 --- a/src/render_context.h +++ b/src/render_context.h @@ -17,11 +17,27 @@ typedef struct RenderContext { VkSurfaceKHR windowSurface; VkSwapchainKHR swapchain; List swapchainImages; // + List swapchainViews; // + List swapchainBuffers; // VkFormat swapchainFormat; VkExtent2D swapchainExtent; + VkShaderModule fragmentShader; + VkShaderModule vertexShader; + + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; + + VkCommandPool commandPool; + VkCommandBuffer commandBuffer; + VkQueue graphicsQueue; VkQueue presentQueue; + + VkSemaphore imageAvailable; + VkSemaphore renderFinished; + VkFence inFlight; } RenderContext; // number of queue family indexes, used for QueueFamilyIndexes.as_array