summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c761
1 files changed, 716 insertions, 45 deletions
diff --git a/main.c b/main.c
index 7063979..b3648cb 100644
--- a/main.c
+++ b/main.c
@@ -1,12 +1,90 @@
+#define STB_IMAGE_IMPLEMENTATION
+
#include <stdio.h>
#include <vulkan/vulkan.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_vulkan.h>
#include <stdbool.h>
#include <string.h>
+#include <libpng16/png.h>
+#include "linmath.h"
+#include "stb_image.h"
#define MAX_FRAMES_INFLIGHT 2
+typedef mat4x4 mat4;
+
+struct ubo {
+ mat4 model;
+ mat4 view;
+ mat4 proj;
+};
+
+struct vertex {
+ vec3 pos;
+ vec3 color;
+ vec2 texture_coords;
+};
+
+struct vertex vertices[] = {
+ {{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}},
+ {{ 0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}},
+ {{ 0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}},
+ {{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
+
+ {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}},
+ {{ 0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}},
+ {{ 0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}},
+ {{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
+
+/*
+ {{ 0.0f, -0.5f}, {0.445f, 0.09f, 0.727f}},
+
+ {{-0.5f, -1.0f}, {0.445f, 0.09f, 0.727f}},
+ {{-1.0f, -0.5f}, {0.445f, 0.09f, 0.727f}},
+
+ {{ 1.0f, -0.5f}, {0.445f, 0.09f, 0.727f}},
+ {{ 0.5f, -1.0f}, {0.445f, 0.09f, 0.727f}},
+
+ {{ 0.0f, 1.0f}, {0.445f, 0.09f, 0.727f}},
+*/
+};
+
+uint16_t indices[] = {
+ 0, 1, 2, 2, 3, 0,
+ 4, 5, 6, 6, 7, 4
+};
+// uint16_t indices[] = {1, 0, 2, 3, 0, 4, 2, 3, 5};
+
+VkVertexInputBindingDescription get_vertex_description() {
+ return (VkVertexInputBindingDescription) {
+ .binding = 0,
+ .stride = sizeof(struct vertex),
+ .inputRate = VK_VERTEX_INPUT_RATE_VERTEX
+ };
+}
+
+void get_attribute_description(VkVertexInputAttributeDescription out[3]) {
+ out[0] = (VkVertexInputAttributeDescription) {
+ .binding = 0,
+ .location = 0,
+ .format = VK_FORMAT_R32G32B32_SFLOAT,
+ .offset = offsetof(struct vertex, pos)
+ };
+ out[1] = (VkVertexInputAttributeDescription) {
+ .binding = 0,
+ .location = 1,
+ .format = VK_FORMAT_R32G32B32_SFLOAT,
+ .offset = offsetof(struct vertex, color)
+ };
+ out[2] = (VkVertexInputAttributeDescription) {
+ .binding = 0,
+ .location = 2,
+ .format = VK_FORMAT_R32G32_SFLOAT,
+ .offset = offsetof(struct vertex, texture_coords)
+ };
+}
+
static SDL_Window *window = NULL;
static VkDebugUtilsMessengerEXT debug_messenger;
static VkInstance instance = VK_NULL_HANDLE;
@@ -19,6 +97,7 @@ static VkSwapchainKHR swapchain;
static VkFormat swapchain_format;
static VkExtent2D swapchain_extent;
static VkRenderPass render_pass;
+static VkDescriptorSetLayout desc_layout;
static VkPipelineLayout pipeline_layout;
static VkCommandPool command_pool;
static VkCommandBuffer command_buffers[MAX_FRAMES_INFLIGHT];
@@ -26,7 +105,23 @@ static VkPipeline graphics_pipeline;
static VkSemaphore image_avail[MAX_FRAMES_INFLIGHT];
static VkSemaphore render_finished[MAX_FRAMES_INFLIGHT];
static VkFence in_flight_fence[MAX_FRAMES_INFLIGHT];
+static VkBuffer uniform_buffers[MAX_FRAMES_INFLIGHT];
+static VkDeviceMemory uniform_memory[MAX_FRAMES_INFLIGHT];
+static void *mapped_buffers[MAX_FRAMES_INFLIGHT];
+static VkDescriptorPool desc_pool;
+static VkDescriptorSet desc_sets[MAX_FRAMES_INFLIGHT];
static uint32_t current_frame = 0;
+static VkBuffer vertex_buffer;
+static VkDeviceMemory vertex_buffer_memory;
+static VkBuffer index_buffer;
+static VkDeviceMemory index_buffer_memroy;
+static VkImage texture_image;
+static VkDeviceMemory texture_image_memory;
+static VkImageView texture_view;
+static VkSampler texture_sampler;
+static VkImage depth_image;
+static VkDeviceMemory depth_memory;
+static VkImageView depth_image_view;
static struct {
size_t len;
VkImage data[];
@@ -131,6 +226,9 @@ bool found_queue_indx(struct queue_indices inds) {
}
void cleanup_swapchain() {
+ vkDestroyImageView(gpu, depth_image_view, NULL);
+ vkDestroyImage(gpu, depth_image, NULL);
+ vkFreeMemory(gpu, depth_memory, NULL);
for (size_t i = 0; i < framebuffers->len; i++) {
vkDestroyFramebuffer(gpu, framebuffers->data[i], NULL);
}
@@ -146,13 +244,37 @@ void cleanup() {
vkDestroySemaphore(gpu, image_avail[i], NULL);
vkDestroySemaphore(gpu, render_finished[i], NULL);
vkDestroyFence(gpu, in_flight_fence[i], NULL);
+
+ vkDestroyBuffer(gpu, uniform_buffers[i], NULL);
+ vkFreeMemory(gpu, uniform_memory[i], NULL);
}
cleanup_swapchain();
+
+ vkDestroyBuffer(gpu, index_buffer, NULL);
+ vkFreeMemory(gpu, index_buffer_memroy, NULL);
+
+ vkDestroySampler(gpu, texture_sampler, NULL);
+ vkDestroyImageView(gpu, texture_view, NULL);
+ vkDestroyImage(gpu, texture_image, NULL);
+ vkFreeMemory(gpu, texture_image_memory, NULL);
+
+ vkDestroyDescriptorPool(gpu, desc_pool, NULL);
+ vkDestroyDescriptorSetLayout(gpu, desc_layout, NULL);
+
+ vkDestroyBuffer(gpu, vertex_buffer, NULL);
+ vkFreeMemory(gpu, vertex_buffer_memory, NULL);
+
vkDestroyCommandPool(gpu, command_pool, NULL);
+
vkDestroyPipeline(gpu, graphics_pipeline, NULL);
vkDestroyPipelineLayout(gpu, pipeline_layout, NULL);
+
vkDestroyRenderPass(gpu, render_pass, NULL);
vkDestroySurfaceKHR(instance, surface, NULL);
+
+ ((PFN_vkDestroyDebugUtilsMessengerEXT)
+ vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"))(instance, debug_messenger, NULL);
+
vkDestroyDevice(gpu, NULL);
vkDestroyInstance(instance, NULL);
SDL_DestroyWindow(window);
@@ -264,6 +386,9 @@ bool is_device_ok(VkPhysicalDevice dev) {
free(props);
+ VkPhysicalDeviceFeatures supported_features;
+ vkGetPhysicalDeviceFeatures(dev, &supported_features);
+
bool adequate_swapchain = false;
if (swapchain) {
struct swapchain_details details = query_swapchain(dev);
@@ -271,7 +396,8 @@ bool is_device_ok(VkPhysicalDevice dev) {
free_swapchain_details(details);
}
- return found_queue_indx(find_queue_families(dev)) && swapchain && adequate_swapchain;
+ return found_queue_indx(find_queue_families(dev)) && swapchain
+ && adequate_swapchain && supported_features.samplerAnisotropy;
}
void pick_physical_dev() {
@@ -320,7 +446,9 @@ void create_logical_dev() {
},
};
- VkPhysicalDeviceFeatures dev_features = { 0 };
+ VkPhysicalDeviceFeatures dev_features = {
+ .samplerAnisotropy = VK_TRUE
+ };
const char * const ext = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
@@ -401,36 +529,44 @@ void create_swapchain() {
}
+VkImageView create_image_view(VkImage image, VkFormat format, VkImageAspectFlags aspect_flags) {
+ VkImageViewCreateInfo create_info = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+ .image = image,
+ .viewType = VK_IMAGE_VIEW_TYPE_2D,
+ .format = format,
+ .components = {
+ .r = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .g = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .b = VK_COMPONENT_SWIZZLE_IDENTITY,
+ .a = VK_COMPONENT_SWIZZLE_IDENTITY,
+ },
+ .subresourceRange = {
+ .aspectMask = aspect_flags,
+ .baseMipLevel = 0,
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ }
+ };
+
+ VkImageView view;
+
+ VkResult res = vkCreateImageView(gpu, &create_info, NULL, &view);
+ if (res != VK_SUCCESS) {
+ fputs("failed to create image view", stderr);
+ exit(-1);
+ }
+
+ return view;
+}
+
void create_image_views() {
swapchain_image_views = malloc(sizeof(*swapchain_image_views) + sizeof(*swapchain_image_views->data) * swapchain_images->len);
swapchain_image_views->len = swapchain_images->len;
for (size_t i = 0; i < swapchain_images->len; i++) {
- VkImageViewCreateInfo create_info = {
- .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
- .image = swapchain_images->data[i],
- .viewType = VK_IMAGE_VIEW_TYPE_2D,
- .format = swapchain_format,
- .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
- }
- };
-
- VkResult res = vkCreateImageView(gpu, &create_info, NULL, &swapchain_image_views->data[i]);
- if (res != VK_SUCCESS) {
- fputs("failed to create image view", stderr);
- exit(-1);
- }
+ swapchain_image_views->data[i] = create_image_view(swapchain_images->data[i], swapchain_format, VK_IMAGE_ASPECT_COLOR_BIT);
}
}
@@ -447,7 +583,7 @@ struct code *readfile(const char *filename) {
struct code *bytes = malloc(sizeof(*bytes) + sizeof(*bytes->data) * len);
bytes->len = len;
- fread(bytes->data, sizeof(*bytes->data), len, fp);
+ size_t read = fread(bytes->data, sizeof(*bytes->data), len, fp);
fclose(fp);
return bytes;
@@ -493,8 +629,16 @@ void create_graphics_pipeline() {
VkPipelineShaderStageCreateInfo shader_stages[] = { vert_shader_info, frag_shader_info };
+ VkVertexInputBindingDescription desc = get_vertex_description();
+ VkVertexInputAttributeDescription attrs[3];
+ get_attribute_description(attrs);
+
VkPipelineVertexInputStateCreateInfo vertex_input_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ .vertexBindingDescriptionCount = 1,
+ .pVertexBindingDescriptions = &desc,
+ .vertexAttributeDescriptionCount = sizeof(attrs) / sizeof(*attrs),
+ .pVertexAttributeDescriptions = attrs
};
VkPipelineInputAssemblyStateCreateInfo input_assembly = {
@@ -541,7 +685,7 @@ void create_graphics_pipeline() {
.polygonMode = VK_POLYGON_MODE_FILL,
.lineWidth = 1.0f,
.cullMode = VK_CULL_MODE_BACK_BIT,
- .frontFace = VK_FRONT_FACE_CLOCKWISE,
+ .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
.depthBiasEnable = VK_FALSE,
};
@@ -564,8 +708,21 @@ void create_graphics_pipeline() {
.pAttachments = &color_state
};
+ VkPipelineDepthStencilStateCreateInfo depth_stencil = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+ .depthTestEnable = VK_TRUE,
+ .depthWriteEnable = VK_TRUE,
+ .depthCompareOp = VK_COMPARE_OP_LESS,
+ .depthBoundsTestEnable = VK_FALSE,
+ .minDepthBounds = 0.0f,
+ .maxDepthBounds = 1.0,
+ .stencilTestEnable = VK_FALSE,
+ };
+
VkPipelineLayoutCreateInfo pipeline_layout_create_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .setLayoutCount = 1,
+ .pSetLayouts = &desc_layout
};
VkResult res = vkCreatePipelineLayout(gpu, &pipeline_layout_create_info, NULL, &pipeline_layout);
@@ -585,6 +742,7 @@ void create_graphics_pipeline() {
.pMultisampleState = &multisampling,
.pColorBlendState = &color_blending,
.pDynamicState = &dynamic_state_info,
+ .pDepthStencilState = &depth_stencil,
.layout = pipeline_layout,
.renderPass = render_pass,
.subpass = 0,
@@ -602,6 +760,135 @@ void create_graphics_pipeline() {
vkDestroyShaderModule(gpu, vert_shader, NULL);
}
+uint32_t find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags props) {
+ VkPhysicalDeviceMemoryProperties mem_props;
+ vkGetPhysicalDeviceMemoryProperties(phy_gpu, &mem_props);
+
+ for (size_t i = 0; i < mem_props.memoryTypeCount; i++)
+ if (type_filter & (1 << i) && (mem_props.memoryTypes[i].propertyFlags & props) == props)
+ return i;
+
+ fputs("failed to find memory type", stderr);
+ exit(-1);
+}
+
+void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage,
+ VkMemoryPropertyFlags props, VkBuffer *buffer, VkDeviceMemory *buffer_memory) {
+ VkBufferCreateInfo buffer_info = {
+ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+ .size = size,
+ .usage = usage,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE
+ };
+
+ VkResult res = vkCreateBuffer(gpu, &buffer_info, NULL, buffer);
+ if (res != VK_SUCCESS) {
+ fputs("failed to create vertex buffer", stderr);
+ exit(-1);
+ }
+
+ VkMemoryRequirements mem_reqs;
+ vkGetBufferMemoryRequirements(gpu, *buffer, &mem_reqs);
+
+ VkMemoryAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .allocationSize = mem_reqs.size,
+ .memoryTypeIndex = find_memory_type(mem_reqs.memoryTypeBits, props)
+ };
+
+ res = vkAllocateMemory(gpu, &alloc_info, NULL, buffer_memory);
+ if (res != VK_SUCCESS) {
+ fputs("failed to allocate memory", stderr);
+ exit(-1);
+ }
+
+ vkBindBufferMemory(gpu, *buffer, *buffer_memory, 0);
+}
+
+VkCommandBuffer being_single_command() {
+ VkCommandBufferAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .commandPool = command_pool,
+ .commandBufferCount = 1
+ };
+
+ VkCommandBuffer cmd_buf;
+ vkAllocateCommandBuffers(gpu, &alloc_info, &cmd_buf);
+
+ VkCommandBufferBeginInfo begin_info = {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
+ };
+
+ vkBeginCommandBuffer(cmd_buf, &begin_info);
+
+ return cmd_buf;
+}
+
+void end_single_command(VkCommandBuffer command_buffer) {
+ vkEndCommandBuffer(command_buffer);
+
+ VkSubmitInfo submit_info = {
+ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+ .commandBufferCount = 1,
+ .pCommandBuffers = &command_buffer
+ };
+
+ vkQueueSubmit(gfx_queue, 1, &submit_info, VK_NULL_HANDLE);
+ vkQueueWaitIdle(gfx_queue);
+
+ vkFreeCommandBuffers(gpu, command_pool, 1, &command_buffer);
+}
+
+void copy_buffer_to_image(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) {
+ VkCommandBuffer command_buffer = being_single_command();
+
+ VkBufferImageCopy region = {
+ .bufferRowLength = 0,
+ .bufferOffset = 0,
+ .bufferImageHeight = 0,
+ .imageSubresource = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ },
+ .imageOffset = { 0, 0, 0 },
+ .imageExtent = { width, height, 1 }
+ };
+
+ vkCmdCopyBufferToImage(command_buffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
+
+ end_single_command(command_buffer);
+}
+
+void copy_buffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) {
+ VkCommandBuffer cmd_buf = being_single_command();
+ vkCmdCopyBuffer(cmd_buf, src, dst, 1, &(VkBufferCopy) { .size = size });
+ end_single_command(cmd_buf);
+}
+
+void create_vertex_buffer() {
+ VkBuffer tmp_buffer;
+ VkDeviceMemory tmp_mem;
+ create_buffer(sizeof(vertices), VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &tmp_buffer, &tmp_mem);
+
+ void *data;
+ vkMapMemory(gpu, tmp_mem, 0, sizeof(vertices), 0, &data);
+ memcpy(data, vertices, sizeof(vertices));
+ vkUnmapMemory(gpu, tmp_mem);
+
+ create_buffer(sizeof(vertices), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertex_buffer, &vertex_buffer_memory);
+
+ copy_buffer(tmp_buffer, vertex_buffer, sizeof(vertices));
+
+ vkDestroyBuffer(gpu, tmp_buffer, NULL);
+ vkFreeMemory(gpu, tmp_mem, NULL);
+}
+
void create_render_pass() {
VkAttachmentDescription color_attach = {
.format = swapchain_format,
@@ -619,25 +906,44 @@ void create_render_pass() {
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
};
+ VkAttachmentDescription depth_attach = {
+ .format = VK_FORMAT_D32_SFLOAT,
+ .samples = VK_SAMPLE_COUNT_1_BIT,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+ .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
+ };
+
+ VkAttachmentReference depth_attach_ref = {
+ .attachment = 1,
+ .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
+ };
+
VkSubpassDescription subpass = {
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.colorAttachmentCount = 1,
- .pColorAttachments = &color_attach_ref
+ .pColorAttachments = &color_attach_ref,
+ .pDepthStencilAttachment = &depth_attach_ref
};
VkSubpassDependency dep = {
.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_WRITE_BIT
+ .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
+ .srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
+ .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
+ .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
};
+ VkAttachmentDescription attachs[] = { color_attach, depth_attach };
+
VkRenderPassCreateInfo create_info = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
- .attachmentCount = 1,
- .pAttachments = &color_attach,
+ .attachmentCount = sizeof(attachs) / sizeof(*attachs),
+ .pAttachments = attachs,
.subpassCount = 1,
.pSubpasses = &subpass,
.dependencyCount = 1,
@@ -657,13 +963,14 @@ void create_framebuffers() {
for (size_t i = 0; i < swapchain_image_views->len; i++) {
VkImageView attachs[] = {
- swapchain_image_views->data[i]
+ swapchain_image_views->data[i],
+ depth_image_view
};
VkFramebufferCreateInfo framebuffer_info = {
.sType =VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = render_pass,
- .attachmentCount = 1,
+ .attachmentCount = sizeof(attachs) / sizeof(*attachs),
.pAttachments = attachs,
.width = swapchain_extent.width,
.height = swapchain_extent.height,
@@ -720,7 +1027,10 @@ void record_command_buffer(VkCommandBuffer buffer, uint32_t image_index) {
exit(-1);
}
- VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
+ VkClearValue clear_color[] = {
+ { .color = {0.0f, 0.0f, 0.0f, 1.0f}},
+ { .depthStencil = { 1.0f, 0 }}
+ };
VkRenderPassBeginInfo render_pass_info = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = render_pass,
@@ -729,8 +1039,8 @@ void record_command_buffer(VkCommandBuffer buffer, uint32_t image_index) {
.extent = swapchain_extent,
.offset = {0, 0}
},
- .clearValueCount = 1,
- .pClearValues = &clear_color
+ .clearValueCount = sizeof(clear_color) / sizeof(*clear_color),
+ .pClearValues = clear_color
};
vkCmdBeginRenderPass(buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
@@ -752,7 +1062,16 @@ void record_command_buffer(VkCommandBuffer buffer, uint32_t image_index) {
};
vkCmdSetScissor(buffer, 0, 1, &scissor);
- vkCmdDraw(buffer, 3, 1, 0, 0);
+
+ VkBuffer vertex_buffers[] = { vertex_buffer };
+ VkDeviceSize offsets[] = {0};
+ vkCmdBindVertexBuffers(buffer, 0, 1, vertex_buffers, offsets);
+ vkCmdBindIndexBuffer(buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16);
+
+ vkCmdBindDescriptorSets(buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ pipeline_layout, 0, 1, &desc_sets[current_frame], 0, NULL);
+
+ vkCmdDrawIndexed(buffer, sizeof(indices) / sizeof(*indices), 1, 0, 0, 0);
vkCmdEndRenderPass(buffer);
@@ -780,6 +1099,316 @@ void create_sync_objects() {
}
}
+void create_index_buffer() {
+ VkBuffer tmp_buffer;
+ VkDeviceMemory tmp_mem;
+ create_buffer(sizeof(indices), VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &tmp_buffer, &tmp_mem);
+
+ void *data;
+ vkMapMemory(gpu, tmp_mem, 0, sizeof(indices), 0, &data);
+ memcpy(data, indices, sizeof(indices));
+ vkUnmapMemory(gpu, tmp_mem);
+
+ create_buffer(sizeof(indices), VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &index_buffer, &index_buffer_memroy);
+
+ copy_buffer(tmp_buffer, index_buffer, sizeof(indices));
+
+ vkDestroyBuffer(gpu, tmp_buffer, NULL);
+ vkFreeMemory(gpu, tmp_mem, NULL);
+}
+
+void create_descriptor_layout() {
+ VkDescriptorSetLayoutBinding layout_bind[] = {
+ {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ .descriptorCount = 1,
+ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT
+ }, {
+ .binding = 1,
+ .descriptorCount = 1,
+ .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .pImmutableSamplers = NULL,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
+ }
+ };
+
+
+
+ VkDescriptorSetLayoutCreateInfo desc_create_info = {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ .bindingCount = sizeof(layout_bind) / sizeof(*layout_bind),
+ .pBindings = layout_bind
+ };
+
+ VkResult res = vkCreateDescriptorSetLayout(gpu, &desc_create_info, NULL, &desc_layout);
+ if (res != VK_SUCCESS) {
+ fputs("failed to create descriptor set layout", stderr);
+ exit(-1);
+ }
+}
+
+void create_uniform_buffers() {
+ for (size_t i = 0; i < MAX_FRAMES_INFLIGHT; i++) {
+ create_buffer(sizeof(struct ubo), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
+ &uniform_buffers[i], &uniform_memory[i]);
+ vkMapMemory(gpu, uniform_memory[i], 0, sizeof(struct ubo), 0, &mapped_buffers[i]);
+ }
+}
+
+void create_descriptor_pool() {
+ VkDescriptorPoolSize pool_size[] = {
+ {
+ .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ .descriptorCount = MAX_FRAMES_INFLIGHT
+ }, {
+ .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .descriptorCount = MAX_FRAMES_INFLIGHT
+ }
+ };
+
+ VkDescriptorPoolCreateInfo pool_info = {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+ .poolSizeCount = sizeof(pool_size) / sizeof(*pool_size),
+ .pPoolSizes = pool_size,
+ .maxSets = MAX_FRAMES_INFLIGHT
+ };
+
+ VkResult res = vkCreateDescriptorPool(gpu, &pool_info, NULL, &desc_pool);
+ if (res != VK_SUCCESS) {
+ fputs("failed to create descriptor pool", stderr);
+ exit(-1);
+ }
+}
+
+void create_descriptor_sets() {
+ VkDescriptorSetLayout layouts[MAX_FRAMES_INFLIGHT] = {
+ desc_layout,
+ desc_layout
+ };
+
+ VkDescriptorSetAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ .descriptorPool = desc_pool,
+ .descriptorSetCount = MAX_FRAMES_INFLIGHT,
+ .pSetLayouts = layouts
+ };
+
+ VkResult res = vkAllocateDescriptorSets(gpu, &alloc_info, desc_sets);
+ if (res != VK_SUCCESS) {
+ fputs("failed to allocate descriptor sets", stderr);
+ exit(-1);
+ }
+
+ for (size_t i = 0; i < MAX_FRAMES_INFLIGHT; i++) {
+ VkDescriptorBufferInfo buffer_info = {
+ .buffer = uniform_buffers[i],
+ .offset = 0,
+ .range = sizeof(struct ubo)
+ };
+
+ VkDescriptorImageInfo image_info = {
+ .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ .imageView = texture_view,
+ .sampler = texture_sampler
+ };
+
+ VkWriteDescriptorSet desc_write[] = {
+ {
+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ .dstSet = desc_sets[i],
+ .dstBinding = 0,
+ .dstArrayElement = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ .descriptorCount = 1,
+ .pBufferInfo = &buffer_info,
+ }, {
+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ .dstSet = desc_sets[i],
+ .dstBinding = 1,
+ .dstArrayElement = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ .descriptorCount = 1,
+ .pImageInfo = &image_info,
+ }
+ };
+
+ vkUpdateDescriptorSets(gpu, sizeof(desc_write) / sizeof(*desc_write), desc_write, 0, NULL);
+ }
+}
+
+void create_image(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling,
+ VkImageUsageFlags usage, VkMemoryPropertyFlags props, VkImage *img, VkDeviceMemory *memory) {
+ VkImageCreateInfo image_info = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+ .imageType = VK_IMAGE_TYPE_2D,
+ .extent = {
+ .width = width,
+ .height = height,
+ .depth = 1
+ },
+ .mipLevels = 1,
+ .arrayLayers = 1,
+ .format = format,
+ .tiling = tiling,
+ .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+ .usage = usage,
+ .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+ .samples = VK_SAMPLE_COUNT_1_BIT
+ };
+
+ VkResult res = vkCreateImage(gpu, &image_info, NULL, img);
+ if (res != VK_SUCCESS) {
+ fputs("failed to create image", stderr);
+ exit(-1);
+ }
+
+ VkMemoryRequirements mem_reqs;
+ vkGetImageMemoryRequirements(gpu, *img, &mem_reqs);
+
+ VkMemoryAllocateInfo alloc_info = {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ .allocationSize = mem_reqs.size,
+ .memoryTypeIndex = find_memory_type(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
+ };
+
+ res = vkAllocateMemory(gpu, &alloc_info, NULL, memory);
+ if (res != VK_SUCCESS) {
+ fputs("failed to allocate memory", stderr);
+ exit(-1);
+ }
+
+ vkBindImageMemory(gpu, *img, *memory, 0);
+}
+
+void transition_image_layout(VkImage image, VkFormat format, VkImageLayout old_layout, VkImageLayout new_layout) {
+ VkCommandBuffer command_buffer = being_single_command();
+ VkImageMemoryBarrier barrier = {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+ .oldLayout = old_layout,
+ .newLayout = new_layout,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .image = image,
+ .subresourceRange = {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .baseMipLevel = 0,
+ .levelCount = 1,
+ .baseArrayLayer = 0,
+ .layerCount = 1
+ },
+ .srcAccessMask = 0,
+ .dstAccessMask = 0
+ };
+
+ VkPipelineStageFlags src_flags, dst_flags;
+
+ if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ src_flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ dst_flags = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
+ && new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
+ barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+
+ src_flags = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ dst_flags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ } else {
+ fputs("unsupported layout transition", stderr);
+ exit(-1);
+ }
+
+ vkCmdPipelineBarrier(command_buffer, src_flags, dst_flags, 0, 0, NULL, 0, NULL, 1, &barrier);
+
+ end_single_command(command_buffer);
+}
+
+void create_texture_image() {
+ int32_t width, height, channels;
+
+ stbi_uc *pixels = stbi_load("pfp.png", &width, &height, &channels, STBI_rgb_alpha);
+ if (!pixels) {
+ fputs("failed to open pfp.png", stderr);
+ exit(-1);
+ }
+
+ VkDeviceSize image_size = width * height * 4;
+
+ VkBuffer tmp_buffer;
+ VkDeviceMemory tmp_mem;
+
+ create_buffer(image_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &tmp_buffer, &tmp_mem);
+
+ void *data;
+ vkMapMemory(gpu, tmp_mem, 0, image_size, 0, &data);
+ memcpy(data, pixels, image_size);
+ vkUnmapMemory(gpu, tmp_mem);
+
+ stbi_image_free(pixels);
+
+ create_image(width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &texture_image, &texture_image_memory);
+
+ transition_image_layout(texture_image, VK_FORMAT_R8G8B8A8_SRGB,
+ VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ copy_buffer_to_image(tmp_buffer, texture_image, width, height);
+
+ transition_image_layout(texture_image, VK_FORMAT_R8G8B8A8_SRGB,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+ vkDestroyBuffer(gpu, tmp_buffer, NULL);
+ vkFreeMemory(gpu, tmp_mem, NULL);
+}
+
+void create_texture_view() {
+ texture_view = create_image_view(texture_image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
+}
+
+void create_texture_sampler() {
+ VkPhysicalDeviceProperties props;
+ vkGetPhysicalDeviceProperties(phy_gpu, &props);
+ VkSamplerCreateInfo sampler_info = {
+ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+ .magFilter = VK_FILTER_LINEAR,
+ .minFilter = VK_FILTER_LINEAR,
+ .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
+ .anisotropyEnable = VK_TRUE,
+ .maxAnisotropy = props.limits.maxSamplerAnisotropy,
+ .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
+ .unnormalizedCoordinates = VK_FALSE,
+ .compareEnable = VK_FALSE,
+ .compareOp = VK_COMPARE_OP_ALWAYS,
+ .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
+ .mipLodBias = 0.0f,
+ .minLod = 0.0f,
+ .maxLod = 0.0f
+ };
+
+ VkResult res = vkCreateSampler(gpu, &sampler_info, NULL, &texture_sampler);
+ if (res != VK_SUCCESS) {
+ fputs("failed to create image sampler", stderr);
+ exit(-1);
+ }
+}
+
+void create_depth_resources() {
+ VkFormat depth_format = VK_FORMAT_D32_SFLOAT;
+ create_image(swapchain_extent.width, swapchain_extent.height, VK_FORMAT_D32_SFLOAT, VK_IMAGE_TILING_OPTIMAL,
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &depth_image, &depth_memory);
+
+ depth_image_view = create_image_view(depth_image, VK_FORMAT_D32_SFLOAT, VK_IMAGE_ASPECT_DEPTH_BIT);
+}
+
void recreate_swapchain() {
int32_t width = 0, height = 0;
SDL_GetWindowSize(window, &width, &height);
@@ -795,6 +1424,7 @@ void recreate_swapchain() {
create_swapchain();
create_image_views();
+ create_depth_resources();
create_framebuffers();
}
@@ -831,13 +1461,41 @@ void init() {
create_swapchain();
create_image_views();
create_render_pass();
+ create_descriptor_layout();
create_graphics_pipeline();
- create_framebuffers();
create_command_pool();
+ create_depth_resources();
+ create_framebuffers();
+ create_texture_image();
+ create_texture_view();
+ create_texture_sampler();
+ create_vertex_buffer();
+ create_index_buffer();
+ create_uniform_buffers();
+ create_descriptor_pool();
+ create_descriptor_sets();
create_command_buffers();
create_sync_objects();
}
+void update_uniform_buffer(uint32_t current_image) {
+ static double rotate = 0.1;
+ struct ubo ubo = {0};
+ mat4 id;
+ mat4x4_identity(id);
+ mat4x4_rotate(ubo.model, id, 0, 0, 1.0f, rotate * 90);
+ mat4x4_translate_in_place(ubo.model, 0, 0, 1);
+
+ mat4x4_look_at(ubo.view, (vec3){ 2, 2, 2 }, (vec3){ 0, 0, 1}, (vec3){ 0, 0, 1 });
+
+ mat4x4_perspective(ubo.proj, 45, swapchain_extent.width / (float) swapchain_extent.height, 0.1f, 10.0f);
+
+ ubo.proj[1][1] *= -1;
+
+ memcpy(mapped_buffers[current_frame], &ubo, sizeof(ubo));
+ rotate += 0.0001;
+}
+
void draw() {
vkWaitForFences(gpu, 1, &in_flight_fence[current_frame], VK_TRUE, UINT64_MAX);
@@ -845,9 +1503,9 @@ void draw() {
VkResult res = vkAcquireNextImageKHR(gpu, swapchain, UINT64_MAX, image_avail[current_frame], VK_NULL_HANDLE, &image_index);
switch (res) {
case VK_SUCCESS:
+ case VK_SUBOPTIMAL_KHR:
break;
case VK_ERROR_OUT_OF_DATE_KHR:
- case VK_SUBOPTIMAL_KHR:
recreate_swapchain();
return;
default:
@@ -873,6 +1531,8 @@ void draw() {
.pCommandBuffers = &command_buffers[current_frame]
};
+ update_uniform_buffer(current_frame);
+
res = vkQueueSubmit(gfx_queue, 1, &submit_info, in_flight_fence[current_frame]);
if (res != VK_SUCCESS) {
fputs("failed to submit draw command buffer", stderr);
@@ -889,7 +1549,18 @@ void draw() {
.pImageIndices = &image_index
};
- vkQueuePresentKHR(present_queue, &present_info);
+ res = vkQueuePresentKHR(present_queue, &present_info);
+ switch (res) {
+ case VK_SUCCESS:
+ break;
+ case VK_SUBOPTIMAL_KHR:
+ case VK_ERROR_OUT_OF_DATE_KHR:
+ recreate_swapchain();
+ return;
+ default:
+ fputs("failed to acquire swapchain images", stderr);
+ exit(-1);
+ }
current_frame = (current_frame + 1) % MAX_FRAMES_INFLIGHT;
}