|
|
@ -7,8 +7,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
#define GLM_FORCE_RADIANS
|
|
|
|
#define GLM_FORCE_RADIANS
|
|
|
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
|
|
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
|
|
|
#include <cglm/mat4.h>
|
|
|
|
#include <cglm/vec3.h>
|
|
|
|
#include <cglm/vec4.h>
|
|
|
|
#include <cglm/vec2.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
@ -40,6 +40,11 @@ typedef struct SwapchainImagesStruct {
|
|
|
|
uint32_t count;
|
|
|
|
uint32_t count;
|
|
|
|
} SwapchainImages;
|
|
|
|
} SwapchainImages;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct AllocatedBufferStruct {
|
|
|
|
|
|
|
|
VkBuffer buffer;
|
|
|
|
|
|
|
|
VkDeviceMemory memory;
|
|
|
|
|
|
|
|
} AllocatedBuffer;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct VulkanContextStruct {
|
|
|
|
typedef struct VulkanContextStruct {
|
|
|
|
VkInstance instance;
|
|
|
|
VkInstance instance;
|
|
|
|
VkDebugUtilsMessengerEXT debug_messenger;
|
|
|
|
VkDebugUtilsMessengerEXT debug_messenger;
|
|
|
@ -77,10 +82,22 @@ typedef struct VulkanContextStruct {
|
|
|
|
|
|
|
|
|
|
|
|
VkPipelineLayout triangle_pipeline_layout;
|
|
|
|
VkPipelineLayout triangle_pipeline_layout;
|
|
|
|
VkPipeline triangle_pipeline;
|
|
|
|
VkPipeline triangle_pipeline;
|
|
|
|
|
|
|
|
AllocatedBuffer triangle_buffer;
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t current_frame;
|
|
|
|
uint32_t current_frame;
|
|
|
|
} VulkanContext;
|
|
|
|
} 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[] = {
|
|
|
|
const char * validation_layers[] = {
|
|
|
|
"VK_LAYER_KHRONOS_validation",
|
|
|
|
"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);
|
|
|
|
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) {
|
|
|
|
GLFWwindow* init_window(int width, int height) {
|
|
|
|
glfwInit();
|
|
|
|
glfwInit();
|
|
|
|
glfwSetErrorCallback(glfw_error);
|
|
|
|
glfwSetErrorCallback(glfw_error);
|
|
|
@ -699,11 +740,69 @@ VkPipelineLayout create_pipeline_layout(VkDevice device, uint32_t set_count, VkD
|
|
|
|
return layout;
|
|
|
|
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) {
|
|
|
|
VkPipeline create_graphics_pipeline(VkDevice device, VkExtent2D extent, VkPipelineLayout layout, VkRenderPass render_pass) {
|
|
|
|
VkShaderModule vert_shader = load_shader_file(2048, "vert.spv", device);
|
|
|
|
VkShaderModule vert_shader = load_shader_file(2048, "shader_src/basic.vert.spv", device);
|
|
|
|
fprintf(stderr, "Loaded vert_shader: %p\n", vert_shader);
|
|
|
|
VkShaderModule frag_shader = load_shader_file(2048, "shader_src/basic.frag.spv", device);
|
|
|
|
VkShaderModule frag_shader = load_shader_file(2048, "frag.spv", device);
|
|
|
|
|
|
|
|
fprintf(stderr, "Loaded frag_shader: %p\n", frag_shader);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
|
|
|
VkPipelineShaderStageCreateInfo shader_stages[2] = {};
|
|
|
|
shader_stages[0].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT;
|
|
|
|
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 = {};
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
|
|
|
|
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
|
|
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
|
|
vertex_input_info.vertexBindingDescriptionCount = 0;
|
|
|
|
vertex_input_info.vertexBindingDescriptionCount = 1;
|
|
|
|
vertex_input_info.pVertexBindingDescriptions = 0;
|
|
|
|
vertex_input_info.pVertexBindingDescriptions = vertex_binding_descriptions();
|
|
|
|
vertex_input_info.vertexAttributeDescriptionCount = 0;
|
|
|
|
vertex_input_info.vertexAttributeDescriptionCount = 2;
|
|
|
|
vertex_input_info.pVertexAttributeDescriptions = 0;
|
|
|
|
vertex_input_info.pVertexAttributeDescriptions = vertex_attribute_descriptions();
|
|
|
|
|
|
|
|
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo input_assemvly_info = {};
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo input_assemvly_info = {};
|
|
|
|
input_assemvly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_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;
|
|
|
|
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 = {};
|
|
|
|
VkCommandBufferBeginInfo begin_info = {};
|
|
|
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
|
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
|
|
begin_info.flags = 0;
|
|
|
|
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);
|
|
|
|
vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
|
|
|
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
|
|
|
|
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 = {};
|
|
|
|
VkViewport viewport = {};
|
|
|
|
viewport.x = 0.0f;
|
|
|
|
viewport.x = 0.0f;
|
|
|
|
viewport.y = 0.0f;
|
|
|
|
viewport.y = 0.0f;
|
|
|
@ -884,7 +987,7 @@ VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t
|
|
|
|
scissor.extent = extent;
|
|
|
|
scissor.extent = extent;
|
|
|
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
|
|
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
|
|
|
|
|
|
|
|
|
|
|
vkCmdDraw(command_buffer, 3, 1, 0, 0);
|
|
|
|
vkCmdDraw(command_buffer, num_vertices, 1, 0, 0);
|
|
|
|
vkCmdEndRenderPass(command_buffer);
|
|
|
|
vkCmdEndRenderPass(command_buffer);
|
|
|
|
|
|
|
|
|
|
|
|
return vkEndCommandBuffer(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;
|
|
|
|
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;
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1140,7 +1250,7 @@ VkResult draw_frame(VulkanContext* context) {
|
|
|
|
return result;
|
|
|
|
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) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|