diff --git a/demo.c b/demo.c index 9d93bdc..98e8578 100644 --- a/demo.c +++ b/demo.c @@ -11,6 +11,8 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define CLAMP(x, min, max) MAX((min), MIN(x, (max))) +#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0])) + #define QUEUE_FAMILY_PROP_BUFFER_SIZE 16 #define EXT_PROP_BUFFER_SIZE 256 #define SURFACE_FMT_BUFFER_SIZE 64 @@ -19,6 +21,10 @@ #define MAX_SHADER_SIZE (8 * 1024) +typedef struct { + float position[2], colour[3]; +} vertex_t; + static const char *layers[] = { "VK_LAYER_KHRONOS_validation" }; static const char *extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, @@ -32,7 +38,13 @@ static const char frag_shader_code[] = { #embed FRAG_SHADER_SPV }; -#define NEXTENSIONS (sizeof(extensions) / sizeof(extensions[0])) +static const vertex_t vertices[] = { + { { 0.0, -0.5 }, { 1.0, 0.0, 0.0 } }, + { { 0.5, 0.5 }, { 0.0, 1.0, 0.0 } }, + { { -0.5, 0.5 }, { 0.0, 0.0, 1.0 } }, +}; + +#define NEXTENSIONS NELEMS(extensions) static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) @@ -297,8 +309,33 @@ int main() }; // Set up input configuration + const VkVertexInputBindingDescription input_binding_descs[] = { + { + .binding = 0, + .stride = sizeof(vertex_t), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }, + }; + const VkVertexInputAttributeDescription input_attribute_descs[] = { + { + .binding = 0, + .location = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(vertex_t, position), + }, + { + .binding = 0, + .location = 1, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(vertex_t, colour), + }, + }; const VkPipelineVertexInputStateCreateInfo vertex_input_config = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = NELEMS(input_binding_descs), + .pVertexBindingDescriptions = input_binding_descs, + .vertexAttributeDescriptionCount = NELEMS(input_attribute_descs), + .pVertexAttributeDescriptions = input_attribute_descs, }; const VkPipelineInputAssemblyStateCreateInfo input_assembly_config = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, @@ -440,6 +477,57 @@ int main() assert(result == VK_SUCCESS); } + // Create vertex buffer + const VkBufferCreateInfo vertex_buffer_config = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = sizeof(vertices), + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + VkBuffer vertex_buffer; + result = vkCreateBuffer( + dev, &vertex_buffer_config, nullptr, &vertex_buffer); + assert(result == VK_SUCCESS); + + // Allocate memory to vertex buffer + const VkMemoryPropertyFlags mem_flags + = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + VkMemoryRequirements mem_requirements; + vkGetBufferMemoryRequirements(dev, vertex_buffer, &mem_requirements); + VkPhysicalDeviceMemoryProperties mem_props; + vkGetPhysicalDeviceMemoryProperties(physical_dev, &mem_props); + uint32_t mem_type = UINT32_MAX; + for (unsigned i = 0; i < mem_props.memoryTypeCount; ++i) { + const bool valid_type + = (mem_requirements.memoryTypeBits & (1 << i)) != 0; + const bool has_flags + = (mem_props.memoryTypes[i].propertyFlags & mem_flags) + == mem_flags; + if (valid_type && has_flags) { + mem_type = i; + break; + } + } + assert(mem_type != UINT32_MAX); + VkMemoryAllocateInfo allocate_config = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = mem_requirements.size, + .memoryTypeIndex = mem_type, + }; + VkDeviceMemory vertex_buffer_mem; + result = vkAllocateMemory( + dev, &allocate_config, nullptr, &vertex_buffer_mem); + assert(result == VK_SUCCESS); + vkBindBufferMemory(dev, vertex_buffer, vertex_buffer_mem, 0); + + // Copy vertex data into vertex buffer + void *vertex_data; + vkMapMemory( + dev, vertex_buffer_mem, 0, sizeof(vertices), 0, &vertex_data); + memcpy(vertex_data, vertices, sizeof(vertices)); + vkUnmapMemory(dev, vertex_buffer_mem); + // Create command pool const VkCommandPoolCreateInfo cmd_pool_config = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, @@ -512,10 +600,12 @@ int main() vkCmdBeginRenderPass( cmd_buf, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); - // Bind graphics pipeline and draw + // Bind graphics pipeline and vertex buffer, then draw vkCmdBindPipeline( cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - vkCmdDraw(cmd_buf, 4, 1, 0, 0); + vkCmdBindVertexBuffers( + cmd_buf, 0, 1, &vertex_buffer, &(VkDeviceSize) { 0 }); + vkCmdDraw(cmd_buf, NELEMS(vertices), 1, 0, 0); // Finish render pass and end writing to command buffer vkCmdEndRenderPass(cmd_buf); @@ -568,6 +658,8 @@ int main() vkDestroyImageView(dev, swapchain_img_views[i], nullptr); } vkDestroySwapchainKHR(dev, swapchain, nullptr); + vkDestroyBuffer(dev, vertex_buffer, nullptr); + vkFreeMemory(dev, vertex_buffer_mem, nullptr); vkDestroyDevice(dev, nullptr); vkDestroySurfaceKHR(inst, surface, nullptr); vkDestroyInstance(inst, nullptr); diff --git a/vert.glsl b/vert.glsl index e7fe154..3e2a810 100644 --- a/vert.glsl +++ b/vert.glsl @@ -1,20 +1,11 @@ #version 450 -vec2 positions[3] = vec2[]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); - -vec3 colours[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) in vec2 position; +layout(location = 1) in vec3 colour; layout(location = 0) out vec3 frag_colour; void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - frag_colour = colours[gl_VertexIndex]; + gl_Position = vec4(position, 0.0, 1.0); + frag_colour = colour; }