diff --git a/include/localeVulkan.hpp b/include/localeVulkan.hpp index dfbb7358..cd43f16a 100644 --- a/include/localeVulkan.hpp +++ b/include/localeVulkan.hpp @@ -43,6 +43,9 @@ enum Errors VULKAN_SHADER_UNABLE_TO_CREATE_SHADER, VULKAN_PIPELAYOUT_CREATION_FAILED, VULKAN_RENDERPASS_CREATION_FAILED, + VULKAN_DESCRIPTOR_POOL_CREATION_FAILED, + VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED, + VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED, VULKAN_GRAPHICSPIPELINE_CREATION_FAILED, VULKAN_FRAMEBUFFERS_CREATION_FAILED, VULKAN_RECORD_COMMAND_BUFFER_FAILED, @@ -90,6 +93,12 @@ std::array, LAST_LANGUAGE> vulkanErrorMess "Failed to create pipeline layout", /* VULKAN_RENDERPASS_CREATION_FAILED */ "Failed to create render pass", + /* VULKAN_DESCRIPTOR_POOL_CREATION_FAILED */ + "Failed to create descriptor pool", + /* VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED */ + "Failed to allocate descriptor sets", + /* VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED */ + "Failed to create descriptor set layout", /* VULKAN_GRAPHICSPIPELINE_CREATION_FAILED */ "Failed to create graphics pipeline", /* VULKAN_FRAMEBUFFERS_CREATION_FAILED */ diff --git a/shaders/shader.vert b/shaders/shader.vert index cb40e1e9..af32e037 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -1,11 +1,17 @@ #version 450 +layout(binding = 0) uniform UniformBufferObject { + mat4 model; + mat4 view; + mat4 proj; +} ubo; + layout(location = 0) in vec2 inPosition; layout(location = 1) in vec3 inColor; layout(location = 0) out vec3 fragColor; void main() { - gl_Position = vec4(inPosition, 0.0, 1.0); + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); fragColor = inColor; } \ No newline at end of file diff --git a/src/vulkanBase.cpp b/src/vulkanBase.cpp index f3b7852b..a0599e42 100644 --- a/src/vulkanBase.cpp +++ b/src/vulkanBase.cpp @@ -34,7 +34,9 @@ #include "logger.hpp" #include "window.hpp" +#define GLM_FORCE_RADIANS #include +#include #include #include @@ -82,6 +84,9 @@ enum VULKAN_ERROR VULKAN_ERROR_SHADER_CREATION_FAILED, VULKAN_ERROR_PIPELINE_LAYOUT_CREATION_FAILED, VULKAN_ERROR_RENDERPASS_CREATION_FAILED, + VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED, + VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED, + VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED, VULKAN_ERROR_GRAPHICSPIPELINE_CREATION_FAILED, VULKAN_ERROR_FRAMEBUFFERS_CREATION_FAILED, VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED, @@ -131,6 +136,12 @@ struct Vertex }; +struct UniformBufferObject { + alignas(16) glm::mat4 model; + alignas(16) glm::mat4 view; + alignas(16) glm::mat4 proj; +}; + /** * @brief Wrapper for Vulan buffer. Holds allocation data; * @@ -207,7 +218,10 @@ VkExtent2D gSwapchainExtent; std::vector gShaderModules; VkRenderPass gRenderPass = VK_NULL_HANDLE; VkPipelineLayout gPipelineLayout = VK_NULL_HANDLE; +VkDescriptorSetLayout gDescriptorSetLayout = VK_NULL_HANDLE; VkPipeline gGraphicsPipeline = VK_NULL_HANDLE; +VkDescriptorPool gDescriptorPool = {}; +std::vector gDescriptorSets = {}; std::vector gSwapchainFramebuffers = {}; std::vector gImageAvailableSemaphores = {}; std::vector gRenderFinishedSemaphores = {}; @@ -218,6 +232,9 @@ Buffer gVertexBuffer = {}; Buffer gVertexStagingBuffer = {}; Buffer gIndexBuffer = {}; Buffer gIndexStagingBuffer = {}; +std::vector gUniformBuffers = {}; +std::vector gUniformBuffersMappedMemory = {}; + /** * @brief Helper function. Creates a buffer object @@ -316,6 +333,13 @@ static uint8_t createVertexBuffer(); */ static uint8_t createIndexBuffer(); +/** + * @brief Create a Uniform Buffers + * + * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + */ +static uint8_t createUniformBuffers(); + /** * @brief Allocate Command Buffers * @@ -339,14 +363,6 @@ static uint8_t createSwapchain(); */ static uint8_t createSwapchainImageViews(); -/** - * @brief Creates shader stages from hardcoded shader paths. Changes input - * - * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: - * VULKAN_ERROR_SHADER_FILE_OPEN_FAILED - * VULKAN_ERROR_SHADER_CREATION_FAILED - */ - /** * @brief Creates shader stages from hardcoded shader paths. Changes input * @@ -426,6 +442,13 @@ static uint8_t createRenderPass(); */ static uint8_t createPipelineLayout(); +/** + * @brief Create a Descriptor Set Layout + * + * @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors: + */ +static uint8_t createDescriptorSetLayout(); + /** * @brief Create Graphics Pipeline * @@ -630,7 +653,7 @@ static uint8_t createInstance() /* Check if selected layers are supported*/ for (auto &layer : gEnabledInstanceLayersNames) { if(std::find_if(layerProperties.begin(), layerProperties.end(), [&layer](const VkLayerProperties& lp) { - return strcmp(lp.layerName, layer); + return strcmp(lp.layerName, layer) == 0; }) == std::end(layerProperties)) { LOGF << vulkanErrorMesssages[VULKAN_LAYER_NOT_SUPPORTED] << layer; return VULKAN_ERROR_LAYER_NOT_SUPPORTED; @@ -640,7 +663,7 @@ static uint8_t createInstance() /* Check if selected extensions are supported*/ for (auto &extension : gEnabledInstanceExtensionsNames) { if(std::find_if(extensionsProperties.begin(), extensionsProperties.end(), [&extension](const VkExtensionProperties& ep) { - return strcmp(ep.extensionName, extension); + return strcmp(ep.extensionName, extension) == 0; }) == std::end(extensionsProperties)) { LOGF << vulkanErrorMesssages[VULKAN_EXTENSION_NOT_SUPPORTED] << extension; return VULKAN_ERROR_EXTENSION_NOT_SUPPORTED; @@ -711,7 +734,8 @@ static uint8_t pickPhysicalDevice() vkGetPhysicalDeviceFeatures(pPhysicalDevices[physicalDeviceIdx], &deviceFeatures); /* Expect discrete graphics device type */ - if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { + if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU + || deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) { /* Application MUST have geometry shader */ if (deviceFeatures.geometryShader) { gPhysicalDevice = pPhysicalDevices[physicalDeviceIdx]; @@ -948,6 +972,84 @@ static uint8_t createIndexBuffer() return VULKAN_ERROR_NO_ERROR; } +static uint8_t createUniformBuffers() +{ + VkDeviceSize bufferSize = sizeof(UniformBufferObject); + + gUniformBuffers.resize(SWAP_BUFFER_COUNT); + gUniformBuffersMappedMemory.resize(SWAP_BUFFER_COUNT); + + for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) { + createBuffer(bufferSize, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_HOST, + VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, + gUniformBuffers[i]); + + VmaAllocationInfo allocInfo; + vmaGetAllocationInfo(gAllocator, gUniformBuffers[i].allocation, &allocInfo); + gUniformBuffersMappedMemory[i] = allocInfo.pMappedData; + } + + return VULKAN_ERROR_NO_ERROR; +} + +static uint8_t createDescriptorPool() +{ + VkDescriptorPoolSize poolSize{}; + poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSize.descriptorCount = static_cast(SWAP_BUFFER_COUNT); + + VkDescriptorPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = 1; + poolInfo.pPoolSizes = &poolSize; + + poolInfo.maxSets = static_cast(SWAP_BUFFER_COUNT); + if (vkCreateDescriptorPool(gDevice, &poolInfo, nullptr, &gDescriptorPool) != VK_SUCCESS) { + LOGF << vulkanErrorMesssages[VULKAN_DESCRIPTOR_POOL_CREATION_FAILED]; + return VULKAN_ERROR_DESCRIPTOR_POOL_CREATION_FAILED; + } + + return VULKAN_ERROR_NO_ERROR; +} + +static uint8_t createDescriptorSets() +{ + std::vector layouts(SWAP_BUFFER_COUNT, gDescriptorSetLayout); + VkDescriptorSetAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = gDescriptorPool; + allocInfo.descriptorSetCount = static_cast(SWAP_BUFFER_COUNT); + allocInfo.pSetLayouts = layouts.data(); + + gDescriptorSets.resize(SWAP_BUFFER_COUNT); + if (vkAllocateDescriptorSets(gDevice, &allocInfo, gDescriptorSets.data()) != VK_SUCCESS) { + LOGF << vulkanErrorMesssages[VULKAN_DESCRIPTOR_SETS_ALLOCATION_FAILED]; + return VULKAN_ERROR_DESCRIPTOR_SETS_ALLOCATION_FAILED; + } + + for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) { + VkDescriptorBufferInfo bufferInfo{}; + bufferInfo.buffer = gUniformBuffers[i].buffer; + bufferInfo.offset = 0; + bufferInfo.range = sizeof(UniformBufferObject); + + VkWriteDescriptorSet descriptorWrite{}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = gDescriptorSets[i]; + descriptorWrite.dstBinding = 0; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets(gDevice, 1, &descriptorWrite, 0, nullptr); + } + + return VULKAN_ERROR_NO_ERROR; +} + static uint8_t allocateCommandBuffers() { VkCommandBufferAllocateInfo allocateInfo; @@ -1236,7 +1338,7 @@ static void fillRasterizationInfo(VkPipelineRasterizationStateCreateInfo* raster rasterizer->rasterizerDiscardEnable = VK_FALSE; /* Disable/Enable output to framebuffer*/ rasterizer->polygonMode = VK_POLYGON_MODE_FILL; rasterizer->cullMode = VK_CULL_MODE_BACK_BIT; - rasterizer->frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer->frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rasterizer->depthBiasEnable = VK_FALSE; rasterizer->depthBiasConstantFactor = 0.0f; rasterizer->depthBiasClamp = 0.0f; @@ -1334,8 +1436,8 @@ static uint8_t createPipelineLayout() createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; createInfo.pNext = nullptr; createInfo.flags = 0U; - createInfo.setLayoutCount = 0; - createInfo.pSetLayouts = nullptr; + createInfo.setLayoutCount = 1U; + createInfo.pSetLayouts = &gDescriptorSetLayout; createInfo.pushConstantRangeCount = 0U; createInfo.pPushConstantRanges = nullptr; @@ -1349,6 +1451,31 @@ static uint8_t createPipelineLayout() return VULKAN_ERROR_NO_ERROR; } +static uint8_t createDescriptorSetLayout() +{ + VkDescriptorSetLayoutCreateInfo layoutInfo; + VkDescriptorSetLayoutBinding uboLayoutBinding; + + uboLayoutBinding.binding = 0; + uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uboLayoutBinding.descriptorCount = 1; + uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + uboLayoutBinding.pImmutableSamplers = nullptr; + + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.pNext = nullptr; + layoutInfo.flags = 0U; + layoutInfo.bindingCount = 1U; + layoutInfo.pBindings = &uboLayoutBinding; + + if (vkCreateDescriptorSetLayout(gDevice, &layoutInfo, nullptr, &gDescriptorSetLayout) != VK_SUCCESS) { + LOGF << vulkanErrorMesssages[VULKAN_DESCRIPTORSETLAYOUT_CREATION_FAILED]; + return VULKAN_ERROR_DESCRIPTORSETLAYOUT_CREATION_FAILED; + } + + return VULKAN_ERROR_NO_ERROR; +} + static uint8_t createGraphicsPipeline() { uint8_t status = VULKAN_ERROR_NO_ERROR; @@ -1477,6 +1604,7 @@ static uint8_t recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t image vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets); vkCmdBindIndexBuffer(commandBuffer, gIndexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, gPipelineLayout, 0, 1, &gDescriptorSets[gCurrentFrame], 0, nullptr); vkCmdDrawIndexed(commandBuffer, static_cast(indices.size()), 1, 0, 0, 0); @@ -1516,6 +1644,21 @@ static uint8_t createSyncObjects() return VULKAN_ERROR_NO_ERROR; } +static void updateUniformBuffer(uint32_t currentImage) +{ + static auto startTime = std::chrono::high_resolution_clock::now(); + + auto currentTime = std::chrono::high_resolution_clock::now(); + float time = std::chrono::duration(currentTime - startTime).count(); + + UniformBufferObject ubo{}; + ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + ubo.proj = glm::perspective(glm::radians(45.0f), gSwapchainExtent.width / (float) gSwapchainExtent.height, 0.1f, 10.0f); + ubo.proj[1][1] *= -1; + memcpy(gUniformBuffersMappedMemory[currentImage], &ubo, sizeof(ubo)); +} + static void cleanupSwapchain() { vkDeviceWaitIdle(gDevice); @@ -1550,16 +1693,20 @@ uint8_t initVulkan() STATUS_CHECK(pickPhysicalDevice()); STATUS_CHECK(createDevice()); STATUS_CHECK(createMemoryAllocator()); - STATUS_CHECK(createCommandPools()); - STATUS_CHECK(createVertexBuffer()); - STATUS_CHECK(createIndexBuffer()); - STATUS_CHECK(allocateCommandBuffers()); STATUS_CHECK(createSwapchain()); STATUS_CHECK(createSwapchainImageViews()); STATUS_CHECK(createRenderPass()); + STATUS_CHECK(createDescriptorSetLayout()); STATUS_CHECK(createPipelineLayout()); STATUS_CHECK(createGraphicsPipeline()); STATUS_CHECK(createFrambuffers()); + STATUS_CHECK(createCommandPools()); + STATUS_CHECK(createVertexBuffer()); + STATUS_CHECK(createIndexBuffer()); + STATUS_CHECK(createUniformBuffers()); + STATUS_CHECK(createDescriptorPool()); + STATUS_CHECK(createDescriptorSets()); + STATUS_CHECK(allocateCommandBuffers()); STATUS_CHECK(createSyncObjects()); return status; } @@ -1580,6 +1727,8 @@ void drawFrame() return; } + updateUniformBuffer(gCurrentFrame); + /* Only reset the fence if we are submitting work */ vkResetFences(gDevice, 1, &gInFlightFences[gCurrentFrame]); @@ -1626,7 +1775,12 @@ void drawFrame() void deinitVulkan() { cleanupSwapchain(); + for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) { + vmaDestroyBuffer(gAllocator, gUniformBuffers[i].buffer, gUniformBuffers[i].allocation); + } + vkDestroyDescriptorPool(gDevice, gDescriptorPool, nullptr); + vkDestroyDescriptorSetLayout(gDevice, gDescriptorSetLayout, nullptr); vmaDestroyBuffer(gAllocator, gVertexBuffer.buffer, gVertexBuffer.allocation); vmaDestroyBuffer(gAllocator, gVertexStagingBuffer.buffer, gVertexStagingBuffer.allocation); vmaDestroyBuffer(gAllocator, gIndexBuffer.buffer, gIndexBuffer.allocation);