summaryrefslogtreecommitdiff
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
parent22128c747e0817f09c11b004016e6d7c518c1523 (diff)
graphics pipeline
-rw-r--r--Makefile2
-rw-r--r--files/shaders/shader1.frag6
-rw-r--r--files/shaders/shader1.vert12
-rw-r--r--src/common.h30
-rw-r--r--src/device.c328
-rw-r--r--src/device.h21
6 files changed, 376 insertions, 23 deletions
diff --git a/Makefile b/Makefile
index 0009173..f4d58ba 100644
--- a/Makefile
+++ b/Makefile
@@ -49,7 +49,7 @@ $(BIND)/$(NAME): $(COBJS)
# Extra Tools
-RUN_CMD := $(BIND)/$(NAME)
+RUN_CMD := cd $(BIND) && ./$(NAME)
UNITY := unity
$(BIND)/$(UNITY): $(CSRCS)
diff --git a/files/shaders/shader1.frag b/files/shaders/shader1.frag
index f30417b..7c5b0e7 100644
--- a/files/shaders/shader1.frag
+++ b/files/shaders/shader1.frag
@@ -1,7 +1,9 @@
#version 450
-layout (location = 0) out vec4 outColor;
+layout(location = 0) in vec3 fragColor;
+
+layout(location = 0) out vec4 outColor;
void main() {
- outColor = vec4(1.0, 0.0, 0.0, 1.0);
+ outColor = vec4(fragColor, 1.0);
}
diff --git a/files/shaders/shader1.vert b/files/shaders/shader1.vert
index c5d117f..f5b2f8d 100644
--- a/files/shaders/shader1.vert
+++ b/files/shaders/shader1.vert
@@ -1,10 +1,20 @@
#version 450
+layout(location = 0) out vec3 fragColor;
+
vec2 positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(0.5, 0.5),
- vec2(-0.5, 0.5));
+ vec2(-0.5, 0.5)
+);
+
+vec3 colors[3] = vec3[](
+ vec3(1.0, 0.0, 0.0),
+ vec3(0.0, 1.0, 0.0),
+ vec3(0.0, 0.0, 1.0)
+);
void main() {
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
+ fragColor = colors[gl_VertexIndex];
}
diff --git a/src/common.h b/src/common.h
index 1c80ab8..27d8404 100644
--- a/src/common.h
+++ b/src/common.h
@@ -27,4 +27,34 @@ void *xmalloc(size_t size);
void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *ptr, size_t size);
+#define F_LOAD_FILE_ALIGNED(T) \
+ static int load_file_##T##_aligned( \
+ char *path, size_t *size, u32 *buf) \
+ { \
+ int ret = 1; \
+ \
+ FILE *fp = fopen(path, "rb"); \
+ if(!fp) { \
+ err("fopen: %s: %s", path, strerror(errno)); \
+ return 1; \
+ } \
+ \
+ fseek(fp, 0, SEEK_END); \
+ *size = (size_t)ftell(fp); \
+ *size += (*size % sizeof(u32)); \
+ \
+ if(buf == NULL) { \
+ ret = 0; \
+ goto exit; \
+ } \
+ \
+ fseek(fp, 0, SEEK_SET); \
+ fread(buf, sizeof(u32), *size/sizeof(u32), fp); \
+ \
+ return 0; \
+ exit: \
+ fclose(fp); \
+ return ret; \
+ }
+
#endif
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)
diff --git a/src/device.h b/src/device.h
index 3491b8a..05bdbc1 100644
--- a/src/device.h
+++ b/src/device.h
@@ -19,14 +19,29 @@ typedef struct device {
VkPhysicalDevice physical_device;
VkDevice logical_device;
+
VkQueue graphics_queue;
VkQueue present_queue;
- VkSwapchainKHR swap_chain;
VkSurfaceKHR surface;
+
+ struct swap_chain {
+ VkSwapchainKHR swap_chain;
+
+ VkImage *images;
+ VkImageView *image_views;
+ u32 nimages;
+
+ VkFormat image_format;
+ VkExtent2D extent;
+ } swap_chain;
+
+ struct pipeline {
+ VkRenderPass render_pass;
+ VkPipelineLayout layout;
+ VkPipeline pipeline;
+ } pipeline;
- VkImage *swap_chain_images;
- u32 nimages;
} * device_t;
struct device_info {