summaryrefslogtreecommitdiff
path: root/src/device.c
diff options
context:
space:
mode:
authorkartofen <mladenovnasko0@gmail.com>2023-10-20 19:31:31 +0300
committerkartofen <mladenovnasko0@gmail.com>2023-10-20 19:31:31 +0300
commit5115eb592d1477b355770eee9d6b913481d4859f (patch)
treebad0ddf43cea533a91bd1fa36caf6942f1c97b21 /src/device.c
parent22128c747e0817f09c11b004016e6d7c518c1523 (diff)
graphics pipeline
Diffstat (limited to 'src/device.c')
-rw-r--r--src/device.c328
1 files changed, 312 insertions, 16 deletions
diff --git a/src/device.c b/src/device.c
index 75a727d..a200e5e 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1,15 +1,20 @@
#include <string.h>
+#include <errno.h>
#include <vulkan/vulkan.h>
#include "device.h"
#include "common.h"
// TODO: rename device.c/.h
-// TODO: add error checking
+// TODO: add more error checking
// TODO: add log output
+// TODO: check for memory leaks
#define CLAMP(val, min, max) (((val) < (min)) ? (min) : ((val) > (max) ? (max) : (val)))
+#define ECHECK(f, ...) if(f(__VA_ARGS__) != 0) { err(#f ": failed"); goto exit; }
+#define FCHECK(f, ...) if(f(__VA_ARGS__) != 0) { err(#f ": failed"); goto fail; }
+
#ifdef DEBUG
char *validation_layers[] = {
"VK_LAYER_KHRONOS_validation"
@@ -34,7 +39,7 @@ struct swap_chain_support_details {
VkSurfaceFormatKHR *formats;
u32 nformats;
- VkPresentModeKHR *present_modes;
+ VkPresentModeKHR *present_modes;
u32 npresent_modes;
};
@@ -47,18 +52,29 @@ static int create_surface(device_t device, struct device_info *info);
static int create_physical_device(device_t device, struct device_info *info);
static int create_logical_device(device_t device, struct device_info *info);
static int create_swap_chain(device_t device, struct device_info *info);
+static int create_render_pass(device_t device, struct device_info *info);
+static int create_pipeline(device_t device, struct device_info *info);
+
+static void destroy_swap_chain(device_t device);
+static void destroy_pipeline(device_t device);
// --- Helper Function ---
static bool device_is_suitable(VkPhysicalDevice phy_device, VkSurfaceKHR surface);
static bool device_has_extension_support(VkPhysicalDevice phy_device);
static int device_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family);
+#define SWCH device->swap_chain
static int swap_chain_support(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct swap_chain_support_details *details);
static void swap_chain_free_support_details(struct swap_chain_support_details *details);
static int swap_chain_choose_format(VkSurfaceFormatKHR* formats, u32 nformats, VkSurfaceFormatKHR *format);
static int swap_chain_choose_present_mode(VkPresentModeKHR *modes, u32 nmodes, VkPresentModeKHR *mode);
static int swap_chain_get_extent(VkSurfaceCapabilitiesKHR capabilities, VkExtent2D *extent);
+#define PPLN device->pipeline
+static int pipeline_load_shader_module(VkDevice device, char *path, VkShaderModule *module);
+
+F_LOAD_FILE_ALIGNED(u32) // from config.h
+
// --- Debug Functions ---
#ifdef DEBUG
static bool instance_has_validation_layers(const char * const *layers, u32 nlayers);
@@ -84,23 +100,30 @@ void DestroyDebugUtilsMessengerEXT(
const VkAllocationCallbacks* pAllocator);
#endif
-#define CHECK(func) if(func(device, info)) { goto fail; }
+#define CCHECK(f) FCHECK(f, device, info)
device_t device_create(struct device_info *info)
{
device_t device = xmalloc(sizeof(struct device));
device->instance = VK_NULL_HANDLE;
device->logical_device = VK_NULL_HANDLE;
- device->swap_chain = VK_NULL_HANDLE;
+
+ PPLN.pipeline = VK_NULL_HANDLE;
+ PPLN.layout = VK_NULL_HANDLE;
+
+ SWCH.swap_chain = VK_NULL_HANDLE;
+ SWCH.nimages = 0;
- CHECK(create_instance);
- CHECK(create_surface);
+ CCHECK(create_instance);
+ CCHECK(create_surface);
#ifdef DEBUG
- CHECK(create_debug_messenger);
+ CCHECK(create_debug_messenger);
#endif
- CHECK(create_physical_device);
- CHECK(create_logical_device);
- CHECK(create_swap_chain)
+ CCHECK(create_physical_device);
+ CCHECK(create_logical_device);
+ CCHECK(create_swap_chain);
+ CCHECK(create_render_pass);
+ CCHECK(create_pipeline);
return device;
fail:
@@ -112,8 +135,8 @@ void device_destroy(device_t device)
{
if(!device) return;
- free(device->swap_chain_images);
- vkDestroySwapchainKHR(device->logical_device, device->swap_chain, NULL);
+ destroy_pipeline(device);
+ destroy_swap_chain(device);
vkDestroyDevice(device->logical_device, NULL);
@@ -315,6 +338,7 @@ exit:
static int create_swap_chain(device_t device, struct device_info *info)
{
+
(void)info;
int ret = 1;
@@ -370,14 +394,46 @@ static int create_swap_chain(device_t device, struct device_info *info)
create_info.oldSwapchain = NULL;
- if (vkCreateSwapchainKHR(device->logical_device, &create_info, NULL, &device->swap_chain) != VK_SUCCESS) {
+ if (vkCreateSwapchainKHR(device->logical_device, &create_info, NULL, &SWCH.swap_chain) != VK_SUCCESS) {
+ err("Couldn't create a Swapchain");
goto exit;
}
- vkGetSwapchainImagesKHR(device->logical_device, device->swap_chain, &device->nimages, NULL);
+ SWCH.image_format = surface_format.format;
+ SWCH.extent = extent;
+
+ vkGetSwapchainImagesKHR(device->logical_device, SWCH.swap_chain, &SWCH.nimages, NULL);
- device->swap_chain_images = xcalloc(device->nimages, sizeof(*device->swap_chain_images));
- vkGetSwapchainImagesKHR(device->logical_device, device->swap_chain, &device->nimages, device->swap_chain_images);
+ SWCH.images = xcalloc(SWCH.nimages, sizeof(*SWCH.images));
+ SWCH.image_views = xcalloc(SWCH.nimages, sizeof(SWCH.image_views));
+
+ vkGetSwapchainImagesKHR(device->logical_device, SWCH.swap_chain, &SWCH.nimages, SWCH.images);
+
+ for(u32 i = 0; i < SWCH.nimages; i++)
+ {
+ VkImageViewCreateInfo create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ create_info.image = SWCH.images[i];
+
+ create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ create_info.format = surface_format.format;
+
+ create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+
+ create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ create_info.subresourceRange.baseMipLevel = 0;
+ create_info.subresourceRange.levelCount = 1;
+ create_info.subresourceRange.baseArrayLayer = 0;
+ create_info.subresourceRange.layerCount = 1;
+
+ if(vkCreateImageView(device->logical_device, &create_info, NULL, &SWCH.image_views[i]) != VK_SUCCESS) {
+ err("Couldn't create image view");
+ goto exit;
+ }
+ }
ret = 0;
exit:
@@ -385,6 +441,219 @@ exit:
return ret;
}
+static void destroy_swap_chain(device_t device)
+{
+ for(u32 i = 0; i < SWCH.nimages; i++) {
+ vkDestroyImageView(device->logical_device, SWCH.image_views[i], NULL);
+ }
+ if(SWCH.nimages != 0) {
+ free(SWCH.images);
+ free(SWCH.image_views);
+ }
+
+ vkDestroySwapchainKHR(device->logical_device, SWCH.swap_chain, NULL);
+}
+
+static int create_render_pass(device_t device, struct device_info *info)
+{
+ (void)info;
+ int ret = 1;
+
+ VkAttachmentDescription color_attachment = {0};
+ color_attachment.format = SWCH.image_format;
+ color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
+ color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+ VkAttachmentReference color_attachment_ref = {0};
+ color_attachment_ref.attachment = 0;
+ color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ VkSubpassDescription subpass = {0};
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.colorAttachmentCount = 1;
+ subpass.pColorAttachments = &color_attachment_ref;
+
+ VkRenderPassCreateInfo render_pass_info = {0};
+ render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ render_pass_info.attachmentCount = 1;
+ render_pass_info.pAttachments = &color_attachment;
+ render_pass_info.subpassCount = 1;
+ render_pass_info.pSubpasses = &subpass;
+
+ if (vkCreateRenderPass(device->logical_device, &render_pass_info, NULL, &PPLN.render_pass) != VK_SUCCESS) {
+ err("Couldnt create a render pass");
+ goto exit;
+ }
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+static int create_pipeline(device_t device, struct device_info *info)
+{
+ (void)info;
+ int ret = 1;
+
+ VkShaderModule vert_shader = VK_NULL_HANDLE;
+ VkShaderModule frag_shader = VK_NULL_HANDLE;
+
+ pipeline_load_shader_module(device->logical_device, "shaders/shader1.vert.spv", &vert_shader);
+ pipeline_load_shader_module(device->logical_device, "shaders/shader1.frag.spv", &frag_shader);
+
+ VkPipelineShaderStageCreateInfo vert_stage = {0};
+ vert_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ vert_stage.stage = VK_SHADER_STAGE_VERTEX_BIT;
+ vert_stage.module = vert_shader;
+ vert_stage.pName = "main";
+
+ VkPipelineShaderStageCreateInfo frag_stage = {0};
+ frag_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ frag_stage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ frag_stage.module = frag_shader;
+ frag_stage.pName = "main";
+
+ VkPipelineShaderStageCreateInfo shader_stages[2] = { vert_stage, frag_stage };
+
+ VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
+
+ VkPipelineDynamicStateCreateInfo dynamic_state = {0};
+ dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ dynamic_state.dynamicStateCount = ARR_SIZE(dynamic_states);
+ dynamic_state.pDynamicStates = dynamic_states;
+
+ // vertex things - hard coded (for now)
+ VkPipelineVertexInputStateCreateInfo vertex_input = {0};
+ vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertex_input.vertexBindingDescriptionCount = 0;
+ vertex_input.pVertexBindingDescriptions = NULL;
+ vertex_input.vertexAttributeDescriptionCount = 0;
+ vertex_input.pVertexAttributeDescriptions = NULL;
+
+ VkPipelineInputAssemblyStateCreateInfo input_assembly = {0};
+ input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ input_assembly.primitiveRestartEnable = VK_FALSE;
+
+ // VkViewport viewport = {0};
+ // viewport.x = 0.0f;
+ // viewport.y = 0.0f;
+ // viewport.width = (float) SWCH.extent.width;
+ // viewport.height = (float) SWCH.extent.height;
+ // viewport.minDepth = 0.0f;
+ // viewport.maxDepth = 1.0f;
+
+ // VkRect2D scissor = {0};
+ // scissor.offset = {0, 0};
+ // scissor.extent = SWCH.extent;
+
+ VkPipelineViewportStateCreateInfo viewport_state = {0};
+ viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewport_state.viewportCount = 1;
+ viewport_state.scissorCount = 1;
+
+ VkPipelineRasterizationStateCreateInfo rasterizer = {0};
+ rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rasterizer.depthClampEnable = VK_FALSE;
+ rasterizer.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
+ rasterizer.lineWidth = 1.0f;
+ rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
+ rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
+
+ rasterizer.depthBiasEnable = VK_FALSE;
+ rasterizer.depthBiasConstantFactor = 0.0f; // Optional
+ rasterizer.depthBiasClamp = 0.0f; // Optional
+ rasterizer.depthBiasSlopeFactor = 0.0f; // Optional
+
+ VkPipelineMultisampleStateCreateInfo multisampling = {0};
+ multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ multisampling.sampleShadingEnable = VK_FALSE;
+ multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+ multisampling.minSampleShading = 1.0f; // Optional
+ multisampling.pSampleMask = NULL; // Optional
+ multisampling.alphaToCoverageEnable = VK_FALSE; // Optional
+ multisampling.alphaToOneEnable = VK_FALSE; // Optional
+
+ VkPipelineColorBlendAttachmentState color_blend_attachment = {0};
+ color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+ color_blend_attachment.blendEnable = VK_FALSE;
+ color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
+ color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
+ color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; // Optional
+ color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
+ color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
+ color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
+
+ VkPipelineColorBlendStateCreateInfo color_blend = {0};
+ color_blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ color_blend.logicOpEnable = VK_FALSE;
+ color_blend.logicOp = VK_LOGIC_OP_COPY; // Optional
+ color_blend.attachmentCount = 1;
+ color_blend.pAttachments = &color_blend_attachment;
+ color_blend.blendConstants[0] = 0.0f; // Optional
+ color_blend.blendConstants[1] = 0.0f; // Optional
+ color_blend.blendConstants[2] = 0.0f; // Optional
+ color_blend.blendConstants[3] = 0.0f; // Optional
+
+ VkPipelineLayoutCreateInfo pipeline_layout_info = {0};
+ pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ pipeline_layout_info.setLayoutCount = 0; // Optional
+ pipeline_layout_info.pSetLayouts = NULL; // Optional
+ pipeline_layout_info.pushConstantRangeCount = 0; // Optional
+ pipeline_layout_info.pPushConstantRanges = NULL; // Optional
+
+ if(vkCreatePipelineLayout(device->logical_device, &pipeline_layout_info, NULL, &PPLN.layout) != VK_SUCCESS) {
+ goto exit;
+ }
+
+ VkGraphicsPipelineCreateInfo pipeline_info = {0};
+ pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ pipeline_info.stageCount = 2;
+ pipeline_info.pStages = shader_stages;
+
+ pipeline_info.pVertexInputState = &vertex_input;
+ pipeline_info.pInputAssemblyState = &input_assembly;
+ pipeline_info.pViewportState = &viewport_state;
+ pipeline_info.pRasterizationState = &rasterizer;
+ pipeline_info.pMultisampleState = &multisampling;
+ pipeline_info.pDepthStencilState = NULL;
+ pipeline_info.pColorBlendState = &color_blend;
+ pipeline_info.pDynamicState = &dynamic_state;
+
+ pipeline_info.layout = PPLN.layout;
+ pipeline_info.renderPass = PPLN.render_pass;
+ pipeline_info.subpass = 0;
+
+ pipeline_info.basePipelineHandle = VK_NULL_HANDLE; // Optional
+ pipeline_info.basePipelineIndex = -1; // Optional
+
+ if(vkCreateGraphicsPipelines(device->logical_device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &PPLN.pipeline) != VK_SUCCESS) {
+ err("Couldnt create a graphics pipeline");
+ goto exit;
+ }
+
+ ret = 0;
+exit:
+ if(frag_shader != VK_NULL_HANDLE)
+ vkDestroyShaderModule(device->logical_device, frag_shader, NULL);
+ if(vert_shader != VK_NULL_HANDLE)
+ vkDestroyShaderModule(device->logical_device, vert_shader, NULL);
+ return ret;
+}
+
+static void destroy_pipeline(device_t device)
+{
+ vkDestroyPipeline(device->logical_device, PPLN.pipeline, NULL);
+ vkDestroyPipelineLayout(device->logical_device, PPLN.layout, NULL);
+ vkDestroyRenderPass(device->logical_device, PPLN.render_pass, NULL);
+}
+
static int device_queue_families(VkPhysicalDevice phy_device, VkSurfaceKHR surface, struct queue_family_idx *queue_family)
{
u32 count = 0;
@@ -516,6 +785,33 @@ static int swap_chain_get_extent(VkSurfaceCapabilitiesKHR capabilities, VkExtent
return 1;
}
+static int pipeline_load_shader_module(VkDevice device, char *path, VkShaderModule *module)
+{
+ int ret = 1;
+
+ size_t size = 0;
+ u32 *buf = NULL;
+
+ ECHECK(load_file_u32_aligned, path, &size, NULL);
+ buf = xmalloc(size);
+ ECHECK(load_file_u32_aligned, path, &size, buf);
+
+ VkShaderModuleCreateInfo create_info = {0};
+ create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ create_info.codeSize = size;
+ create_info.pCode = buf;
+
+ if (vkCreateShaderModule(device, &create_info, NULL, module) != VK_SUCCESS) {
+ err("Couldnt create shader module");
+ goto exit;
+ }
+
+ ret = 0;
+exit:
+ if(buf) free(buf);
+ return ret;
+}
+
#ifdef DEBUG
static bool instance_has_validation_layers(const char * const *layers, u32 nlayers)