|  |  |  | @ -7,8 +7,8 @@ | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #define GLM_FORCE_RADIANS | 
		
	
		
			
				|  |  |  |  | #define GLM_FORCE_DEPTH_ZERO_TO_ONE | 
		
	
		
			
				|  |  |  |  | #include <cglm/mat4.h> | 
		
	
		
			
				|  |  |  |  | #include <cglm/vec4.h> | 
		
	
		
			
				|  |  |  |  | #include <cglm/vec3.h> | 
		
	
		
			
				|  |  |  |  | #include <cglm/vec2.h> | 
		
	
		
			
				|  |  |  |  | #include <stdio.h> | 
		
	
		
			
				|  |  |  |  | #include <string.h> | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -40,6 +40,11 @@ typedef struct SwapchainImagesStruct { | 
		
	
		
			
				|  |  |  |  |   uint32_t count; | 
		
	
		
			
				|  |  |  |  | } SwapchainImages; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | typedef struct AllocatedBufferStruct { | 
		
	
		
			
				|  |  |  |  |   VkBuffer buffer; | 
		
	
		
			
				|  |  |  |  |   VkDeviceMemory memory; | 
		
	
		
			
				|  |  |  |  | } AllocatedBuffer; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | typedef struct VulkanContextStruct { | 
		
	
		
			
				|  |  |  |  |   VkInstance instance; | 
		
	
		
			
				|  |  |  |  |   VkDebugUtilsMessengerEXT debug_messenger; | 
		
	
	
		
			
				
					|  |  |  | @ -77,10 +82,22 @@ typedef struct VulkanContextStruct { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineLayout triangle_pipeline_layout; | 
		
	
		
			
				|  |  |  |  |   VkPipeline triangle_pipeline; | 
		
	
		
			
				|  |  |  |  |   AllocatedBuffer triangle_buffer; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   uint32_t current_frame; | 
		
	
		
			
				|  |  |  |  | } VulkanContext; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | struct Vertex{ | 
		
	
		
			
				|  |  |  |  |   vec2 pos; | 
		
	
		
			
				|  |  |  |  |   vec3 color; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const struct Vertex vertices[] = { | 
		
	
		
			
				|  |  |  |  |   {.pos = { 0.0f, -0.5f}, .color = {1.0f, 0.0f, 0.0f}}, | 
		
	
		
			
				|  |  |  |  |   {.pos = { 0.5f,  0.5f}, .color = {0.0f, 1.0f, 0.0f}}, | 
		
	
		
			
				|  |  |  |  |   {.pos = {-0.5f,  0.5f}, .color = {0.0f, 0.0f, 1.0f}}, | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const char * validation_layers[] = { | 
		
	
		
			
				|  |  |  |  |   "VK_LAYER_KHRONOS_validation", | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
	
		
			
				
					|  |  |  | @ -103,6 +120,30 @@ void glfw_error(int error, const char* description) { | 
		
	
		
			
				|  |  |  |  |   fprintf(stderr, "GLFW_ERR: 0x%02x - %s\n", error, description); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkVertexInputBindingDescription vertex_bindings[1]; | 
		
	
		
			
				|  |  |  |  | VkVertexInputBindingDescription* vertex_binding_descriptions() { | 
		
	
		
			
				|  |  |  |  |   vertex_bindings[0].binding = 0; | 
		
	
		
			
				|  |  |  |  |   vertex_bindings[0].stride = sizeof(struct Vertex); | 
		
	
		
			
				|  |  |  |  |   vertex_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return vertex_bindings; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkVertexInputAttributeDescription vertex_attributes[2]; | 
		
	
		
			
				|  |  |  |  | VkVertexInputAttributeDescription* vertex_attribute_descriptions() { | 
		
	
		
			
				|  |  |  |  |   vertex_attributes[0].binding = 0; | 
		
	
		
			
				|  |  |  |  |   vertex_attributes[0].location = 0; | 
		
	
		
			
				|  |  |  |  |   vertex_attributes[0].format = VK_FORMAT_R32G32_SFLOAT; | 
		
	
		
			
				|  |  |  |  |   vertex_attributes[0].offset = offsetof(struct Vertex, pos); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vertex_attributes[1].binding = 0; | 
		
	
		
			
				|  |  |  |  |   vertex_attributes[1].location = 1; | 
		
	
		
			
				|  |  |  |  |   vertex_attributes[1].format = VK_FORMAT_R32G32B32_SFLOAT; | 
		
	
		
			
				|  |  |  |  |   vertex_attributes[1].offset = offsetof(struct Vertex, color); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return vertex_attributes; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | GLFWwindow* init_window(int width, int height) { | 
		
	
		
			
				|  |  |  |  |   glfwInit(); | 
		
	
		
			
				|  |  |  |  |   glfwSetErrorCallback(glfw_error); | 
		
	
	
		
			
				
					|  |  |  | @ -699,11 +740,69 @@ VkPipelineLayout create_pipeline_layout(VkDevice device, uint32_t set_count, VkD | 
		
	
		
			
				|  |  |  |  |   return layout; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | uint32_t find_memory_type(VkPhysicalDevice physical_device, uint32_t type_filter, VkMemoryPropertyFlags properties) { | 
		
	
		
			
				|  |  |  |  |   VkPhysicalDeviceMemoryProperties memory_properties; | 
		
	
		
			
				|  |  |  |  |   vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for(uint32_t i = 0; i < memory_properties.memoryTypeCount; i++) { | 
		
	
		
			
				|  |  |  |  |     if ((type_filter & (1 << i)) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties) { | 
		
	
		
			
				|  |  |  |  |       return i; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return 0xFFFFFFFF; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | AllocatedBuffer create_vertex_buffer(VkPhysicalDevice physical_device, VkDevice device, void* data, uint32_t size) { | 
		
	
		
			
				|  |  |  |  |   AllocatedBuffer allocated_buffer = {}; | 
		
	
		
			
				|  |  |  |  |   allocated_buffer.buffer = VK_NULL_HANDLE; | 
		
	
		
			
				|  |  |  |  |   allocated_buffer.memory = VK_NULL_HANDLE; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo buffer_info = {}; | 
		
	
		
			
				|  |  |  |  |   buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; | 
		
	
		
			
				|  |  |  |  |   buffer_info.size = size; | 
		
	
		
			
				|  |  |  |  |   buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; | 
		
	
		
			
				|  |  |  |  |   buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkResult result = vkCreateBuffer(device, &buffer_info, 0, &allocated_buffer.buffer); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return allocated_buffer; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkMemoryRequirements memory_requirements; | 
		
	
		
			
				|  |  |  |  |   vkGetBufferMemoryRequirements(device, allocated_buffer.buffer, &memory_requirements); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkMemoryAllocateInfo alloc_info = {}; | 
		
	
		
			
				|  |  |  |  |   alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | 
		
	
		
			
				|  |  |  |  |   alloc_info.allocationSize = memory_requirements.size; | 
		
	
		
			
				|  |  |  |  |   alloc_info.memoryTypeIndex = find_memory_type(physical_device, memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkAllocateMemory(device, &alloc_info, 0, &allocated_buffer.memory); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return allocated_buffer; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkBindBufferMemory(device, allocated_buffer.buffer, allocated_buffer.memory, 0); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return allocated_buffer; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void* buffer_data; | 
		
	
		
			
				|  |  |  |  |   result = vkMapMemory(device, allocated_buffer.memory, 0, buffer_info.size, 0, &buffer_data); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return allocated_buffer; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   memcpy(buffer_data, data, size); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vkUnmapMemory(device, allocated_buffer.memory); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return allocated_buffer; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkPipeline create_graphics_pipeline(VkDevice device, VkExtent2D extent, VkPipelineLayout layout, VkRenderPass render_pass) { | 
		
	
		
			
				|  |  |  |  |   VkShaderModule vert_shader = load_shader_file(2048, "vert.spv", device); | 
		
	
		
			
				|  |  |  |  |   fprintf(stderr, "Loaded vert_shader: %p\n", vert_shader); | 
		
	
		
			
				|  |  |  |  |   VkShaderModule frag_shader = load_shader_file(2048, "frag.spv", device); | 
		
	
		
			
				|  |  |  |  |   fprintf(stderr, "Loaded frag_shader: %p\n", frag_shader); | 
		
	
		
			
				|  |  |  |  |   VkShaderModule vert_shader = load_shader_file(2048, "shader_src/basic.vert.spv", device); | 
		
	
		
			
				|  |  |  |  |   VkShaderModule frag_shader = load_shader_file(2048, "shader_src/basic.frag.spv", device); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineShaderStageCreateInfo shader_stages[2] = {}; | 
		
	
		
			
				|  |  |  |  |   shader_stages[0].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT; | 
		
	
	
		
			
				
					|  |  |  | @ -729,10 +828,10 @@ VkPipeline create_graphics_pipeline(VkDevice device, VkExtent2D extent, VkPipeli | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; | 
		
	
		
			
				|  |  |  |  |   vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; | 
		
	
		
			
				|  |  |  |  |   vertex_input_info.vertexBindingDescriptionCount = 0; | 
		
	
		
			
				|  |  |  |  |   vertex_input_info.pVertexBindingDescriptions = 0; | 
		
	
		
			
				|  |  |  |  |   vertex_input_info.vertexAttributeDescriptionCount = 0; | 
		
	
		
			
				|  |  |  |  |   vertex_input_info.pVertexAttributeDescriptions = 0; | 
		
	
		
			
				|  |  |  |  |   vertex_input_info.vertexBindingDescriptionCount = 1; | 
		
	
		
			
				|  |  |  |  |   vertex_input_info.pVertexBindingDescriptions = vertex_binding_descriptions(); | 
		
	
		
			
				|  |  |  |  |   vertex_input_info.vertexAttributeDescriptionCount = 2; | 
		
	
		
			
				|  |  |  |  |   vertex_input_info.pVertexAttributeDescriptions = vertex_attribute_descriptions(); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineInputAssemblyStateCreateInfo input_assemvly_info = {}; | 
		
	
		
			
				|  |  |  |  |   input_assemvly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; | 
		
	
	
		
			
				
					|  |  |  | @ -844,7 +943,7 @@ VkCommandPool create_command_pool(VkDevice device, uint32_t queue_family) { | 
		
	
		
			
				|  |  |  |  |   return command_pool; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t image_index, VkRenderPass render_pass, VkFramebuffer* framebuffers, VkExtent2D extent, VkPipeline graphics_pipeline) { | 
		
	
		
			
				|  |  |  |  | VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t image_index, VkRenderPass render_pass, VkFramebuffer* framebuffers, VkExtent2D extent, VkPipeline graphics_pipeline, VkBuffer vertex_buffer, uint32_t num_vertices) { | 
		
	
		
			
				|  |  |  |  |   VkCommandBufferBeginInfo begin_info = {}; | 
		
	
		
			
				|  |  |  |  |   begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; | 
		
	
		
			
				|  |  |  |  |   begin_info.flags = 0; | 
		
	
	
		
			
				
					|  |  |  | @ -869,6 +968,10 @@ VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t | 
		
	
		
			
				|  |  |  |  |   vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); | 
		
	
		
			
				|  |  |  |  |   vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBuffer vertex_buffers[] = {vertex_buffer}; | 
		
	
		
			
				|  |  |  |  |   VkDeviceSize offsets[] = {0}; | 
		
	
		
			
				|  |  |  |  |   vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkViewport viewport = {}; | 
		
	
		
			
				|  |  |  |  |   viewport.x = 0.0f; | 
		
	
		
			
				|  |  |  |  |   viewport.y = 0.0f; | 
		
	
	
		
			
				
					|  |  |  | @ -884,7 +987,7 @@ VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t | 
		
	
		
			
				|  |  |  |  |   scissor.extent = extent; | 
		
	
		
			
				|  |  |  |  |   vkCmdSetScissor(command_buffer, 0, 1, &scissor); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vkCmdDraw(command_buffer, 3, 1, 0, 0); | 
		
	
		
			
				|  |  |  |  |   vkCmdDraw(command_buffer, num_vertices, 1, 0, 0); | 
		
	
		
			
				|  |  |  |  |   vkCmdEndRenderPass(command_buffer); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return vkEndCommandBuffer(command_buffer); | 
		
	
	
		
			
				
					|  |  |  | @ -1114,6 +1217,13 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { | 
		
	
		
			
				|  |  |  |  |     context->triangle_pipeline = triangle_pipeline; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   AllocatedBuffer triangle_buffer = create_vertex_buffer(context->physical_device, context->device, (void*)vertices, sizeof(vertices)); | 
		
	
		
			
				|  |  |  |  |   if(triangle_buffer.memory == VK_NULL_HANDLE) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to allocate vulkan buffer for triangle buffer\n"); | 
		
	
		
			
				|  |  |  |  |   } else { | 
		
	
		
			
				|  |  |  |  |     context->triangle_buffer = triangle_buffer; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return context; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -1140,7 +1250,7 @@ VkResult draw_frame(VulkanContext* context) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = record_command_buffer_triangle(context->swapchain_command_buffers[context->current_frame], image_index, context->render_pass, context->swapchain_framebuffers, context->swapchain_extent, context->triangle_pipeline); | 
		
	
		
			
				|  |  |  |  |   result = record_command_buffer_triangle(context->swapchain_command_buffers[context->current_frame], image_index, context->render_pass, context->swapchain_framebuffers, context->swapchain_extent, context->triangle_pipeline, context->triangle_buffer.buffer, 3); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
	
		
			
				
					|  |  |  | 
 |