diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 761 |
1 files changed, 716 insertions, 45 deletions
@@ -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, ®ion); + + 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; } |