|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
#include "render_context.h"
|
|
|
|
|
#include <SDL2/SDL_vulkan.h>
|
|
|
|
|
#include <SDL2/SDL_video.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <vulkan/vulkan_core.h>
|
|
|
|
|
#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,14 +228,17 @@ 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);
|
|
|
|
|
// for simplicities sake get the direct pointers to underlying arrays
|
|
|
|
@ -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);
|
|
|
|
|