From 115e92ec2377e79b712463f4fe9b5c0ccd28f22b Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Mon, 18 Nov 2024 12:51:00 +0300 Subject: [PATCH] add vertex buffers --- main.cpp | 157 +++++++++++++++++++++++++++++++++++++++----- shaders/shader.vert | 17 ++--- 2 files changed, 146 insertions(+), 28 deletions(-) diff --git a/main.cpp b/main.cpp index 49d3dc5..1dfd794 100644 --- a/main.cpp +++ b/main.cpp @@ -11,6 +11,8 @@ #include #include +#include + using TimePoint = std::chrono::time_point; using TimeMs = long; @@ -20,21 +22,32 @@ TimeMs timeDeltaMs(const TimePoint& point) { return timeDelayMs; } -const std::vector deviceExtensions = { +struct SwapChainSupportDetails { + VkSurfaceCapabilitiesKHR capabilities{}; + std::vector formats; + std::vector presentModes; +}; + +struct Vertex { + glm::vec2 pos; + glm::vec3 color; +}; + +const std::vector gDeviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; -const std::vector validationLayers = { +const std::vector gValidationLayers = { #ifdef NDEBUG #else "VK_LAYER_KHRONOS_validation" #endif }; -struct SwapChainSupportDetails { - VkSurfaceCapabilitiesKHR capabilities{}; - std::vector formats; - std::vector presentModes; +const std::vector vertices = { + {{0.f, -0.5f}, {1.f, 0.f, 0.f}}, + {{0.5f, 0.5f}, {0.f, 1.f, 0.f}}, + {{-0.5f, 0.5f}, {0.f, 0.f, 1.f}}, }; class Application { @@ -92,6 +105,10 @@ private: createCommandBuffer(); createSynchronizationObjects(); + + createVertexBuffer(); + allocateVertexBufferMemory(); + sendVertexBufferData(); } void mainLoop() { @@ -132,8 +149,8 @@ private: VkInstanceCreateInfo createInfo{ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &appInfo, - .enabledLayerCount = (uint32_t) validationLayers.size(), - .ppEnabledLayerNames = validationLayers.data(), + .enabledLayerCount = (uint32_t) gValidationLayers.size(), + .ppEnabledLayerNames = gValidationLayers.data(), .enabledExtensionCount = glfwExtensionCount, .ppEnabledExtensionNames = glfwExtensions, }; @@ -150,7 +167,7 @@ private: std::vector availableLayers(layerCount); vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); - for (const auto &requestedLayer: validationLayers) { + for (const auto &requestedLayer: gValidationLayers) { bool presents = false; for (auto &layer: availableLayers) { if (strcmp(requestedLayer, layer.layerName) == 0) { @@ -213,7 +230,7 @@ private: std::vector extensions(extensionsCount); vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionsCount, extensions.data()); - for (const auto &requiredExtension: deviceExtensions) { + for (const auto &requiredExtension: gDeviceExtensions) { bool found = false; for (const auto &extension: extensions) { if (strcmp(requiredExtension, extension.extensionName) == 0) { @@ -306,8 +323,8 @@ private: .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = (uint32_t) queues.size(), .pQueueCreateInfos = queues.data(), - .enabledExtensionCount = (uint32_t) deviceExtensions.size(), - .ppEnabledExtensionNames = deviceExtensions.data(), + .enabledExtensionCount = (uint32_t) gDeviceExtensions.size(), + .ppEnabledExtensionNames = gDeviceExtensions.data(), .pEnabledFeatures = &features, }; @@ -538,10 +555,15 @@ private: .pDynamicStates = dynamicStates.data(), }; + auto attributes = getShaderAttributesDescriptors(); + auto vertexInput = getShaderVertexInputDescription(); + VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = 0, - .vertexAttributeDescriptionCount = 0, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &vertexInput, + .vertexAttributeDescriptionCount = (uint32_t) attributes.size(), + .pVertexAttributeDescriptions = attributes.data(), }; VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo{ @@ -751,6 +773,73 @@ private: } } + uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags flags) { + VkPhysicalDeviceMemoryProperties memoryProperties; + vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memoryProperties); + + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) { + if (typeFilter & (1 << i) && (memoryProperties.memoryTypes[i].propertyFlags & flags) == flags) { + return i; + } + } + + throw std::runtime_error("no suitable memory for vertex buffer found"); + return {}; + } + + void allocateVertexBufferMemory() { + VkMemoryRequirements memoryRequirements; + vkGetBufferMemoryRequirements(mDevice, mVertexBuffer, &memoryRequirements); + + // FIXME : use explicit memory flushing instead of coherent_bit + auto memoryFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + + VkMemoryAllocateInfo allocateInfo = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = memoryRequirements.size, + .memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, memoryFlags), + }; + + if (vkAllocateMemory(mDevice, &allocateInfo, nullptr, &mVertexBufferMemory) != VK_SUCCESS) { + throw std::runtime_error("failed to allocate vertex buffer memory"); + } + + vkBindBufferMemory(mDevice, mVertexBuffer, mVertexBufferMemory, 0); + } + + void sendVertexBufferData() { + size_t memoryLength = vertices.size() * sizeof(vertices[0]); + void* memory; + + if (vkMapMemory(mDevice, mVertexBufferMemory, 0, memoryLength, 0, &memory) != VK_SUCCESS) { + throw std::runtime_error("failed to map memory"); + } + + memcpy(memory, vertices.data(), memoryLength); + vkUnmapMemory(mDevice, mVertexBufferMemory); + } + + void freeVertexBufferMemory() { + vkFreeMemory(mDevice, mVertexBufferMemory, nullptr); + } + + void createVertexBuffer() { + VkBufferCreateInfo createInfo { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = vertices.size() * sizeof(vertices[0]), + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + + if (vkCreateBuffer(mDevice, &createInfo, nullptr, &mVertexBuffer) != VK_SUCCESS) { + throw std::runtime_error("failed to create vertex buffer"); + } + } + + void destroyVertexBuffer() { + vkDestroyBuffer(mDevice, mVertexBuffer, nullptr); + } + void populateGraphicsCommandBuffer(VkCommandBuffer commandBuffer, uint32_t swapChainImageIndex) { VkCommandBufferBeginInfo commandBufferBeginInfo{ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, @@ -794,7 +883,11 @@ private: vkCmdSetViewport(commandBuffer, 0, 1, &viewport); vkCmdSetScissor(commandBuffer, 0, 1, &scissor); - vkCmdDraw(commandBuffer, 3, 1, 0, 0); + VkBuffer vertexBuffers[] = { mVertexBuffer }; + VkDeviceSize offsets[] = { 0 }; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); + + vkCmdDraw(commandBuffer, vertices.size(), 1, 0, 0); vkCmdEndRenderPass(commandBuffer); @@ -876,6 +969,34 @@ private: */ } + static VkVertexInputBindingDescription getShaderVertexInputDescription() { + return { + .binding = 0, + .stride = sizeof(Vertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }; + } + + static std::vector getShaderAttributesDescriptors() { + std::vector out(2); + + out[0] = { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(Vertex, pos), + }; + + out[1] = { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(Vertex, color), + }; + + return out; + } + void destroySynchronizationObjects() { vkDestroySemaphore(mDevice, mSemaphoreImageAcquired, nullptr); vkDestroySemaphore(mDevice, mSemaphoreFramebufferDrawn, nullptr); @@ -883,6 +1004,9 @@ private: } void cleanup() { + freeVertexBufferMemory(); + destroyVertexBuffer(); + destroySynchronizationObjects(); destroyCommandPool(); @@ -940,6 +1064,9 @@ private: VkSemaphore mSemaphoreImageAcquired = VK_NULL_HANDLE; VkSemaphore mSemaphoreFramebufferDrawn = VK_NULL_HANDLE; VkFence mFenceCanStartNewFrame = VK_NULL_HANDLE; + + VkBuffer mVertexBuffer = VK_NULL_HANDLE; + VkDeviceMemory mVertexBufferMemory = VK_NULL_HANDLE; }; int main() { diff --git a/shaders/shader.vert b/shaders/shader.vert index ff4b88b..cb40e1e 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -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 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) in vec2 inPosition; +layout(location = 1) in vec3 inColor; 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; } \ No newline at end of file