From 83ff89daf8338abf7e5d6f84a6ae52af36dcd80e Mon Sep 17 00:00:00 2001 From: Vegard Matthey Date: Mon, 8 Jul 2024 01:37:56 +0200 Subject: [PATCH] inital vertex buffer --- Makefile | 2 +- main.c | 324 +++++++++++++++++++++++++++++++++----------- shaders/shader.frag | 2 +- shaders/shader.vert | 19 +-- 4 files changed, 252 insertions(+), 95 deletions(-) diff --git a/Makefile b/Makefile index e48d25f..92de943 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ LDFLAGS = -lglfw -lvulkan -ldl -lpthread CFLAGS = -g -pedantic -Wall -Wextra -Wshadow -Wunused-macros VulkanApplication: main.c - gcc $(CFLAGS) -o VulkanApplication main.c $(LDFLAGS) + tcc $(CFLAGS) -o VulkanApplication main.c $(LDFLAGS) .PHONY: run clean diff --git a/main.c b/main.c index b16b4bb..a778149 100644 --- a/main.c +++ b/main.c @@ -8,9 +8,15 @@ #include #include +enum bool { + false = 0, + true = 1, +}; +typedef int bool; + const uint32_t WIDTH = 800; const uint32_t HEIGHT = 600; -const int MAX_FRAMES_IN_FLIGHT = 2; +#define MAX_FRAMES_IN_FLIGHT 2 const char* VALIDATION_LAYERS[] = { "VK_LAYER_KHRONOS_validation" }; #define VALIDATION_LAYER_COUNT 1 @@ -19,11 +25,34 @@ const char* DEVICE_EXTENSIONS[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; #define DEVICE_EXTENSION_COUNT 1 #ifdef NDEBUG - const uint32_t enableValidationLayers = 0; + const bool enableValidationLayers = false; #else - const uint32_t enableValidationLayers = 1; + const bool enableValidationLayers = true; #endif +typedef struct Vec2 { + float x; + float y; +} Vec2; + +typedef struct Vec3 { + float x; + float y; + float z; +} Vec3; + +typedef struct Vertex { + Vec2 pos; + Vec3 color; +} Vertex; + +#define VERTEX_COUNT 3 +const Vertex vertices[VERTEX_COUNT] = { + {{0.0f, -0.5f}, {0.0f, 0.0f, 0.0f}}, + {{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}}, + {{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}} +}; + struct VulkanData { VkInstance instance; VkDebugUtilsMessengerEXT debugMessenger; @@ -43,10 +72,14 @@ struct VulkanData { VkPipeline graphicsPipeline; VkFramebuffer swapChainFramebuffers[4]; VkCommandPool commandPool; - VkCommandBuffer commandBuffer; - VkSemaphore imageAvailableSemaphore; - VkSemaphore renderFinishedSemaphore; - VkFence inFlightFence; + VkCommandBuffer commandBuffers[MAX_FRAMES_IN_FLIGHT]; + VkSemaphore imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; + VkSemaphore renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; + VkFence inFlightFences[MAX_FRAMES_IN_FLIGHT]; + uint32_t currentFrame; + bool framebufferResized; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; }; struct SwapChainSupportDetails { @@ -65,11 +98,27 @@ struct QueueFamilyIndices { struct Optional presentFamily; }; -GLFWwindow* initWindow() { +static VkVertexInputBindingDescription getBindingDescription() { + VkVertexInputBindingDescription bindingDescription = { + .binding = 0, + .stride = sizeof(Vertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }; + return bindingDescription; +} + +static void framebufferResizeCallback(GLFWwindow* window, int width, int height) { + printf("INFO: resizing from width: %d, height: %d\n", width, height); + struct VulkanData* app = (struct VulkanData*) glfwGetWindowUserPointer(window); + app->framebufferResized = true; +} + +GLFWwindow* initWindow(struct VulkanData* data) { if (!glfwInit()) { fprintf(stderr, "ERROR: Failed to initialize window\n"); exit(1); } + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", NULL, NULL); if (!window) { @@ -79,11 +128,13 @@ GLFWwindow* initWindow() { } glfwMakeContextCurrent(window); + glfwSetWindowUserPointer(window, data); + glfwSetFramebufferSizeCallback(window, framebufferResizeCallback); return window; } // INDIRECTION: main->run->initVulkan->createInstance -uint32_t checkValidationLayerSupport() { +static bool checkValidationLayerSupport() { uint32_t layerCount; vkEnumerateInstanceLayerProperties(&layerCount, NULL); @@ -103,11 +154,11 @@ uint32_t checkValidationLayerSupport() { } if (!layerFound) { - return 0; + return false; } } - return 1; + return true; } // INDIRECTION: main->run->initVulkan->createInstance @@ -125,7 +176,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( } // INDIRECTION: main->run->initVulkan -void createInstance(struct VulkanData* data) { +static void createInstance(struct VulkanData* data) { if (enableValidationLayers && !checkValidationLayerSupport()) { printf("ERROR: Validation layers requested, but not available\n"); exit(1); @@ -211,7 +262,7 @@ VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMes } -void setupDebugMessenger(struct VulkanData* data) { +static void setupDebugMessenger(struct VulkanData* data) { if (!enableValidationLayers) return; VkDebugUtilsMessengerCreateInfoEXT createInfo = { @@ -227,7 +278,7 @@ void setupDebugMessenger(struct VulkanData* data) { } } -void createSurface(struct VulkanData* data, GLFWwindow* window) { +static void createSurface(struct VulkanData* data, GLFWwindow* window) { VkWaylandSurfaceCreateInfoKHR createInfo = { .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, .display = glfwGetWaylandDisplay(), @@ -243,21 +294,21 @@ void createSurface(struct VulkanData* data, GLFWwindow* window) { } } -void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) { +static void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) { PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); if (func != NULL) { func(instance, debugMessenger, pAllocator); } } -uint32_t clamp(uint32_t value, uint32_t min, uint32_t max) { +static uint32_t clamp(uint32_t value, uint32_t min, uint32_t max) { if (value > max) return max; if (value < min) return min; return value; } -int checkDeviceExtensionSupport(VkPhysicalDevice device) { +static int checkDeviceExtensionSupport(VkPhysicalDevice device) { uint32_t extensionCount; vkEnumerateDeviceExtensionProperties(device, NULL, &extensionCount, NULL); @@ -278,7 +329,7 @@ int checkDeviceExtensionSupport(VkPhysicalDevice device) { return requiredExtensionsFound == DEVICE_EXTENSION_COUNT; } -struct SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR surface) { +static struct SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR surface) { struct SwapChainSupportDetails details; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities); uint32_t formatCount; @@ -297,7 +348,7 @@ struct SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, Vk return details; } -struct QueueFamilyIndices findQueueFamilies(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { +static struct QueueFamilyIndices findQueueFamilies(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { struct QueueFamilyIndices indices = { .graphicsFamily.v = 0, .graphicsFamily.is_some = 0, @@ -334,7 +385,7 @@ struct QueueFamilyIndices findQueueFamilies(VkPhysicalDevice physicalDevice, VkS return indices; } -int isDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { // One could pick the device based on a score. +static bool isDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { // One could pick the device based on a score. struct QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface); VkPhysicalDeviceProperties deviceProperties; @@ -364,7 +415,7 @@ int isDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) { // indices.graphicsFamily.is_some && indices.presentFamily.is_some; } -void pickPhysicalDevice(struct VulkanData* data) { +static void pickPhysicalDevice(struct VulkanData* data) { data->physicalDevice = VK_NULL_HANDLE; uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(data->instance, &deviceCount, NULL); @@ -389,7 +440,7 @@ void pickPhysicalDevice(struct VulkanData* data) { } } -void createLogicalDevice(struct VulkanData* data) { +static void createLogicalDevice(struct VulkanData* data) { struct QueueFamilyIndices indices = findQueueFamilies(data->physicalDevice, data->surface); float queuePriority = 1.0f; @@ -461,7 +512,7 @@ void createLogicalDevice(struct VulkanData* data) { vkGetDeviceQueue(data->device, indices.presentFamily.v, 0, &data->presentQueue); } -VkExtent2D chooseSwapExtent(VkSurfaceCapabilitiesKHR* capabilities, GLFWwindow* window) { +static VkExtent2D chooseSwapExtent(VkSurfaceCapabilitiesKHR* capabilities, GLFWwindow* window) { if (capabilities->currentExtent.width != UINT_MAX) { return capabilities->currentExtent; } else { @@ -480,7 +531,7 @@ VkExtent2D chooseSwapExtent(VkSurfaceCapabilitiesKHR* capabilities, GLFWwindow* } } -VkSurfaceFormatKHR chooseSwapSurfaceFormat(VkSurfaceFormatKHR availableFormats[]) { +static VkSurfaceFormatKHR chooseSwapSurfaceFormat(VkSurfaceFormatKHR availableFormats[]) { for(int i = 0; 1; i++) { VkSurfaceFormatKHR availableFormat = availableFormats[i]; if (availableFormat.format == VK_FORMAT_UNDEFINED) { @@ -493,7 +544,7 @@ VkSurfaceFormatKHR chooseSwapSurfaceFormat(VkSurfaceFormatKHR availableFormats[] return availableFormats[0]; } -VkPresentModeKHR chooseSwapPresentMode(VkPresentModeKHR availablePresentModes[]) { +static VkPresentModeKHR chooseSwapPresentMode(VkPresentModeKHR availablePresentModes[]) { for(int i = 0; 1; i++) { if (availablePresentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { return availablePresentModes[i]; @@ -502,7 +553,7 @@ VkPresentModeKHR chooseSwapPresentMode(VkPresentModeKHR availablePresentModes[]) return VK_PRESENT_MODE_FIFO_KHR; } -void createSwapChain(struct VulkanData* data, GLFWwindow* window) { +static void createSwapChain(struct VulkanData* data, GLFWwindow* window) { struct SwapChainSupportDetails swapChainSupport = querySwapChainSupport(data->physicalDevice, data->surface); VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes); @@ -554,7 +605,7 @@ void createSwapChain(struct VulkanData* data, GLFWwindow* window) { vkGetSwapchainImagesKHR(data->device, data->swapChain, &imageCount, data->swapChainImages); } -void createImageViews(struct VulkanData* data) { +static void createImageViews(struct VulkanData* data) { for (int i = 0; i < data->imageCount; i++) { VkImageViewCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, @@ -577,7 +628,7 @@ void createImageViews(struct VulkanData* data) { } } -void readFile(const char* fileName, char buffer[], int len) { +static void readFile(const char* fileName, char buffer[], int len) { FILE* file = fopen(fileName, "r"); if (!file) { printf("ERROR: File \"%s\" can't be opened \n", fileName); @@ -587,7 +638,7 @@ void readFile(const char* fileName, char buffer[], int len) { fclose(file); } -uint32_t fileSize(const char* fileName) { +static uint32_t fileSize(const char* fileName) { FILE* file = fopen(fileName, "r"); if (!file) { printf("ERROR: File \"%s\" can't be opened \n", fileName); @@ -601,7 +652,7 @@ uint32_t fileSize(const char* fileName) { return size; } -VkShaderModule createShaderModule(const char* code, uint32_t size, VkDevice device) { +static VkShaderModule createShaderModule(const char* code, uint32_t size, VkDevice device) { VkShaderModuleCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .codeSize = size, @@ -614,7 +665,7 @@ VkShaderModule createShaderModule(const char* code, uint32_t size, VkDevice devi return shaderModule; } -void createGraphicsPipeline(struct VulkanData* data) { +static void createGraphicsPipeline(struct VulkanData* data) { const char* vertFileName = "shaders/vert.spv"; uint32_t vertLen = fileSize(vertFileName); char vertShaderCode[vertLen]; @@ -643,7 +694,7 @@ void createGraphicsPipeline(struct VulkanData* data) { .pSpecializationInfo = NULL, }; - VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo}; + VkPipelineShaderStageCreateInfo shaderStages[2] = {vertShaderStageInfo, fragShaderStageInfo}; uint32_t dynamicStateCount = 2; VkDynamicState dynamicStates[] = { @@ -657,12 +708,28 @@ void createGraphicsPipeline(struct VulkanData* data) { .pDynamicStates = dynamicStates, }; + VkVertexInputBindingDescription bindingDescription = getBindingDescription(); + VkVertexInputAttributeDescription attributeDescriptions[2] = { + { + .binding = 0, + .location = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(Vertex, pos), + }, + { + .binding = 0, + .location = 1, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(Vertex, color), + } + }; + VkPipelineVertexInputStateCreateInfo vertexInputInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = 0, - .pVertexBindingDescriptions = NULL, // Optional - .vertexAttributeDescriptionCount = 0, - .pVertexAttributeDescriptions = NULL, // Optional + .vertexBindingDescriptionCount = 1, + .vertexAttributeDescriptionCount = 2, + .pVertexBindingDescriptions = &bindingDescription, + .pVertexAttributeDescriptions = attributeDescriptions, }; VkPipelineInputAssemblyStateCreateInfo inputAssembly = { @@ -781,7 +848,7 @@ void createGraphicsPipeline(struct VulkanData* data) { vkDestroyShaderModule(data->device, vertShaderModule, NULL); } -void createRenderPass(struct VulkanData* data) { +static void createRenderPass(struct VulkanData* data) { VkAttachmentDescription colorAttachment = { .format = data->swapChainImageFormat, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -829,7 +896,7 @@ void createRenderPass(struct VulkanData* data) { } } -void createFramebuffers(struct VulkanData* data) { +static void createFramebuffers(struct VulkanData* data) { for (int i = 0; i < data->imageCount; i++) { VkImageView attachments[] = { data->swapChainImageViews[i] @@ -852,7 +919,7 @@ void createFramebuffers(struct VulkanData* data) { } } -void createCommandPool(struct VulkanData* data) { +static void createCommandPool(struct VulkanData* data) { struct QueueFamilyIndices queueFamilyIndices = findQueueFamilies(data->physicalDevice, data->surface); VkCommandPoolCreateInfo poolInfo = { @@ -867,22 +934,22 @@ void createCommandPool(struct VulkanData* data) { } } -void createCommandBuffer(struct VulkanData* data) { +static void createCommandBuffers(struct VulkanData* data) { VkCommandBufferAllocateInfo allocInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .commandPool = data->commandPool, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1, + .commandBufferCount = MAX_FRAMES_IN_FLIGHT, }; - if (vkAllocateCommandBuffers(data->device, &allocInfo, &data->commandBuffer) != VK_SUCCESS) { + if (vkAllocateCommandBuffers(data->device, &allocInfo, &data->commandBuffers[data->currentFrame]) != VK_SUCCESS) { fprintf(stderr, "ERROR: Failed to allocate command buffers\n"); exit(1); } } -void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, struct VulkanData* data) { +static void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, struct VulkanData* data) { VkCommandBufferBeginInfo beginInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .flags = 0, @@ -909,6 +976,10 @@ void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, str vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->graphicsPipeline); + VkBuffer vertexBuffers[] = {data->vertexBuffer}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); + VkViewport viewport = { .x = 0.0f, .y = 0.0f, @@ -924,7 +995,7 @@ void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, str .extent = data->swapChainExtent, }; vkCmdSetScissor(commandBuffer, 0, 1, &scissor); - vkCmdDraw(commandBuffer, 3, 1, 0, 0); + vkCmdDraw(commandBuffer, VERTEX_COUNT, 1, 0, 0); vkCmdEndRenderPass(commandBuffer); if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { fprintf(stderr, "ERROR: Failed to record command buffer\n"); @@ -932,29 +1003,64 @@ void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, str } } -void drawFrame(struct VulkanData* data) { - vkWaitForFences(data->device, 1, &data->inFlightFence, VK_TRUE, UINT64_MAX); - vkResetFences(data->device, 1, &data->inFlightFence); +static void cleanupSwapChain(struct VulkanData* data) { + for (int i = 0; i < data->imageCount; i++) { + vkDestroyFramebuffer(data->device, data->swapChainFramebuffers[i], NULL); + } + + for (int i = 0; i < data->imageCount; i++) { + vkDestroyImageView(data->device, data->swapChainImageViews[i], NULL); + } + + vkDestroySwapchainKHR(data->device, data->swapChain, NULL); +} + +static void recreateSwapChain(struct VulkanData* data, GLFWwindow* window) { + int width = 0, height = 0; + glfwGetFramebufferSize(window, &width, &height); + while (width == 0 || height == 0) { + glfwGetFramebufferSize(window, &width, &height); + glfwWaitEvents(); + } + vkDeviceWaitIdle(data->device); + cleanupSwapChain(data); + createSwapChain(data, window); + createImageViews(data); + createFramebuffers(data); +} + +static void drawFrame(struct VulkanData* data, GLFWwindow* window) { + vkWaitForFences(data->device, 1, &data->inFlightFences[data->currentFrame], VK_TRUE, UINT64_MAX); uint32_t imageIndex; - vkAcquireNextImageKHR(data->device, data->swapChain, UINT64_MAX, data->imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex); - vkResetCommandBuffer(data->commandBuffer, 0); - recordCommandBuffer(data->commandBuffer, imageIndex, data); + VkResult result = vkAcquireNextImageKHR(data->device, data->swapChain, UINT64_MAX, data->imageAvailableSemaphores[data->currentFrame], VK_NULL_HANDLE, &imageIndex); + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + recreateSwapChain(data, window); + return; + } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + fprintf(stderr, "ERROR: Failed to acquire swap chain image"); + exit(1); + } - VkSemaphore waitSemaphores[] = {data->imageAvailableSemaphore}; + vkResetFences(data->device, 1, &data->inFlightFences[data->currentFrame]); + + vkResetCommandBuffer(data->commandBuffers[data->currentFrame], 0); + recordCommandBuffer(data->commandBuffers[data->currentFrame], imageIndex, data); + + VkSemaphore waitSemaphores[] = {data->imageAvailableSemaphores[data->currentFrame]}; VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; - VkSemaphore signalSemaphores[] = {data->renderFinishedSemaphore}; + VkSemaphore signalSemaphores[] = {data->renderFinishedSemaphores[data->currentFrame]}; VkSubmitInfo submitInfo = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .waitSemaphoreCount = 1, .pWaitSemaphores = waitSemaphores, .pWaitDstStageMask = waitStages, .commandBufferCount = 1, - .pCommandBuffers = &data->commandBuffer, + .pCommandBuffers = &data->commandBuffers[data->currentFrame], .signalSemaphoreCount = 1, .pSignalSemaphores = signalSemaphores, }; - if (vkQueueSubmit(data->graphicsQueue, 1, &submitInfo, data->inFlightFence) != VK_SUCCESS) { + if (vkQueueSubmit(data->graphicsQueue, 1, &submitInfo, data->inFlightFences[data->currentFrame]) != VK_SUCCESS) { fprintf(stderr, "ERROR: Failed to submit draw command buffer\n"); exit(1); } @@ -970,10 +1076,18 @@ void drawFrame(struct VulkanData* data) { .pResults = NULL, }; - vkQueuePresentKHR(data->presentQueue, &presentInfo); + result = vkQueuePresentKHR(data->presentQueue, &presentInfo); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || data->framebufferResized) { + data->framebufferResized = false; + recreateSwapChain(data, window); + } else if (result != VK_SUCCESS) { + fprintf(stderr, "ERROR: Failed to present swap chain image"); + exit(1); + } + data->currentFrame = (data->currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } -void createSyncObjects(struct VulkanData* data) { +static void createSyncObjects(struct VulkanData* data) { VkSemaphoreCreateInfo semaphoreInfo = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, }; @@ -981,16 +1095,68 @@ void createSyncObjects(struct VulkanData* data) { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = VK_FENCE_CREATE_SIGNALED_BIT, }; - if (vkCreateSemaphore(data->device, &semaphoreInfo, NULL, &data->imageAvailableSemaphore) != VK_SUCCESS || - vkCreateSemaphore(data->device, &semaphoreInfo, NULL, &data->renderFinishedSemaphore) != VK_SUCCESS || - vkCreateFence(data->device, &fenceInfo, NULL, &data->inFlightFence) != VK_SUCCESS) { - fprintf(stderr, "ERROR: Failed to create semaphores\n"); - exit(1); + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + if (vkCreateSemaphore(data->device, &semaphoreInfo, NULL, &data->imageAvailableSemaphores[i]) != VK_SUCCESS || + vkCreateSemaphore(data->device, &semaphoreInfo, NULL, &data->renderFinishedSemaphores[i]) != VK_SUCCESS || + vkCreateFence(data->device, &fenceInfo, NULL, &data->inFlightFences[i]) != VK_SUCCESS) { + fprintf(stderr, "ERROR: Failed to create semaphores\n"); + exit(1); + } } } -struct VulkanData initVulkan(GLFWwindow* window) { +uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, struct VulkanData* data) { + VkPhysicalDeviceMemoryProperties memProperties; + vkGetPhysicalDeviceMemoryProperties(data->physicalDevice, &memProperties); + + for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { + if (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties)) { + return i; + } + } + fprintf(stderr, "ERROR: Failed to find suitable memory type\n"); + exit(1); +} + +static void createVertexBuffer(struct VulkanData* data) { + VkBufferCreateInfo bufferInfo = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = sizeof(vertices[0]) * VERTEX_COUNT, + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .flags = 0, + }; + + if (vkCreateBuffer(data->device, &bufferInfo, NULL, &data->vertexBuffer) != VK_SUCCESS) { + fprintf(stderr, "ERROR: Failed to create vertex buffer\n"); + exit(1); + } + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(data->device, data->vertexBuffer, &memRequirements); + + VkMemoryAllocateInfo allocInfo = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = memRequirements.size, + .memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, data), + }; + + if (vkAllocateMemory(data->device, &allocInfo, NULL, &data->vertexBufferMemory) != VK_SUCCESS) { + fprintf(stderr, "ERROR: Failed to allocate vertex buffer memory\n"); + exit(1); + } + + vkBindBufferMemory(data->device, data->vertexBuffer, data->vertexBufferMemory, 0); + void* vertexData; + vkMapMemory(data->device, data->vertexBufferMemory, 0, bufferInfo.size, 0, &vertexData); + memcpy(vertexData, vertices, bufferInfo.size); + vkUnmapMemory(data->device, data->vertexBufferMemory); +} + +static struct VulkanData initVulkan(GLFWwindow* window) { struct VulkanData data; + data.currentFrame = 0; + data.framebufferResized = 0; createInstance(&data); setupDebugMessenger(&data); createSurface(&data, window); @@ -1002,16 +1168,17 @@ struct VulkanData initVulkan(GLFWwindow* window) { createGraphicsPipeline(&data); createFramebuffers(&data); createCommandPool(&data); - createCommandBuffer(&data); + createVertexBuffer(&data); + createCommandBuffers(&data); createSyncObjects(&data); return data; } -void mainLoop(GLFWwindow* window, struct VulkanData* data) { +static void mainLoop(GLFWwindow* window, struct VulkanData* data) { while (!glfwWindowShouldClose(window)) { glfwSwapBuffers(window); glfwPollEvents(); - drawFrame(data); + drawFrame(data, window); int state = glfwGetKey(window, GLFW_KEY_Q); if (state == GLFW_PRESS) { break; @@ -1021,21 +1188,19 @@ void mainLoop(GLFWwindow* window, struct VulkanData* data) { vkDeviceWaitIdle(data->device); } -void cleanup(GLFWwindow* window, struct VulkanData* data) { - vkDestroySemaphore(data->device, data->imageAvailableSemaphore, NULL); - vkDestroySemaphore(data->device, data->renderFinishedSemaphore, NULL); - vkDestroyFence(data->device, data->inFlightFence, NULL); - vkDestroyCommandPool(data->device, data->commandPool, NULL); - for (int i = 0; i < data->imageCount; i++) { - vkDestroyFramebuffer(data->device, data->swapChainFramebuffers[i], NULL); - } +static void cleanup(GLFWwindow* window, struct VulkanData* data) { + cleanupSwapChain(data); + vkDestroyBuffer(data->device, data->vertexBuffer, NULL); + vkFreeMemory(data->device, data->vertexBufferMemory, NULL); vkDestroyPipeline(data->device, data->graphicsPipeline, NULL); vkDestroyPipelineLayout(data->device, data->pipelineLayout, NULL); vkDestroyRenderPass(data->device, data->renderPass, NULL); - for (int i = 0; i < data->imageCount; i++) { - vkDestroyImageView(data->device, data->swapChainImageViews[i], NULL); + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + vkDestroySemaphore(data->device, data->imageAvailableSemaphores[i], NULL); + vkDestroySemaphore(data->device, data->renderFinishedSemaphores[i], NULL); + vkDestroyFence(data->device, data->inFlightFences[i], NULL); } - vkDestroySwapchainKHR(data->device, data->swapChain, NULL); + vkDestroyCommandPool(data->device, data->commandPool, NULL); vkDestroyDevice(data->device, NULL); if (enableValidationLayers) { DestroyDebugUtilsMessengerEXT(data->instance, data->debugMessenger, NULL); @@ -1046,9 +1211,10 @@ void cleanup(GLFWwindow* window, struct VulkanData* data) { glfwTerminate(); } -void run() { - GLFWwindow* window = initWindow(); - struct VulkanData data = initVulkan(window); +static void run() { + struct VulkanData data; + GLFWwindow* window = initWindow(&data); + data = initVulkan(window); mainLoop(window, &data); cleanup(window, &data); } diff --git a/shaders/shader.frag b/shaders/shader.frag index 7c5b0e7..1b69e03 100644 --- a/shaders/shader.frag +++ b/shaders/shader.frag @@ -2,7 +2,7 @@ layout(location = 0) in vec3 fragColor; -layout(location = 0) out vec4 outColor; +layout(location = 1) out vec4 outColor; void main() { outColor = vec4(fragColor, 1.0); diff --git a/shaders/shader.vert b/shaders/shader.vert index f5b2f8d..9f27f54 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -1,20 +1,11 @@ #version 450 +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; + 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]; + gl_Position = vec4(inPosition, 0.0, 1.0); + fragColor = inColor; }