diff --git a/.gitignore b/.gitignore index 85d4b89..dec2f40 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ spacegame .compdb compile_commands.json .cache +*.spv diff --git a/shader_src/basic.vert b/shader_src/basic.vert index f5b2f8d..46d581b 100644 --- a/shader_src/basic.vert +++ b/shader_src/basic.vert @@ -1,20 +1,11 @@ #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) -); +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; -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) -); +layout(location = 0) out vec3 fragColor; void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - fragColor = colors[gl_VertexIndex]; + gl_Position = vec4(inPosition, 0.0, 1.0); + fragColor = inColor; } diff --git a/shader_src/triangle.vert b/shader_src/triangle.vert new file mode 100644 index 0000000..f5b2f8d --- /dev/null +++ b/shader_src/triangle.vert @@ -0,0 +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) +); + +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/main.c b/src/main.c index 4711ca9..75588bb 100644 --- a/src/main.c +++ b/src/main.c @@ -7,8 +7,8 @@ #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE -#include -#include +#include +#include #include #include @@ -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; }