From 3adcc72036df5153bdbe5ed1a3c0f06e945f0ae6 Mon Sep 17 00:00:00 2001 From: "matthias@arch" Date: Thu, 27 Oct 2022 00:50:24 +0200 Subject: [PATCH] moved settings to separate header --- .gitignore | 1 + compile.sh | 16 +- src/Makefile | 5 +- src/main.cpp | 33 +- src/main.hpp | 19 - src/renderer/renderer.cpp | 2 +- src/renderer/renderer.hpp | 24 +- src/renderer/renderer2D.cpp | 259 ++--- src/renderer/renderer2D.hpp | 24 +- src/renderer/renderer3D.cpp | 425 ++++---- src/renderer/renderer3D.hpp | 47 +- src/shader/shader.frag | 16 - src/shader/shader.vert | 25 - src/shader/shader2D.frag | 17 - src/shader/shader2D.vert | 25 - src/shape.cpp | 4 +- src/shape.hpp | 4 +- src/utility/exceptions.cpp | 6 +- src/utility/exceptions.hpp | 6 +- src/utility/texture_atlas.cpp | 66 +- src/utility/texture_atlas.hpp | 17 +- src/utility/texture_manager.cpp | 137 ++- src/utility/texture_manager.hpp | 27 +- src/utility/vulkan_util.cpp | 61 +- src/utility/vulkan_util.hpp | 86 +- src/vertex.cpp | 40 +- src/vertex.hpp | 26 +- src/vk_convert.cpp | 8 +- src/vk_convert.hpp | 11 +- src/vulkan_allocator.cpp | 41 +- src/vulkan_allocator.hpp | 57 +- src/vulkan_instance.cpp | 1695 ++++++++++++++----------------- src/vulkan_instance.hpp | 262 ++--- src/vulkan_settings.hpp | 72 ++ 34 files changed, 1785 insertions(+), 1779 deletions(-) delete mode 100644 src/main.hpp delete mode 100644 src/shader/shader.frag delete mode 100644 src/shader/shader.vert delete mode 100644 src/shader/shader2D.frag delete mode 100644 src/shader/shader2D.vert create mode 100644 src/vulkan_settings.hpp diff --git a/.gitignore b/.gitignore index 99c2920..34aeb90 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ old shaders stb_image.h *.log +vk.xml textures tiny_obj_loader.h vk_enum_string.h diff --git a/compile.sh b/compile.sh index 5a1f797..46e9a64 100755 --- a/compile.sh +++ b/compile.sh @@ -1,12 +1,16 @@ #!/bin/sh WDIR=$HOME/c++/vulkan +SHADER_DIR=$WDIR/shaders +SOURCE_DIR=$WDIR/src/shaders -mkdir -p $WDIR/shaders +mkdir -p "${SHADER_DIR}" -glslc $WDIR/shader.vert -o $WDIR/shaders/vert.spv -glslc $WDIR/shader.frag -o $WDIR/shaders/frag.spv - -glslc $WDIR/shader2D.vert -o $WDIR/shaders/vert2D.spv -glslc $WDIR/shader2D.frag -o $WDIR/shaders/frag2D.spv +for file in $(ls ${SOURCE_DIR}); do + ext="${file##*.}" + if [[ $ext == "vert" ]] || [[ $ext == "frag" ]]; then + echo "compiling ${file}" + glslc ${SOURCE_DIR}/${file} -o ${SHADER_DIR}/$(basename ${file}).spv + fi +done diff --git a/src/Makefile b/src/Makefile index 37a3497..0c7ddf7 100755 --- a/src/Makefile +++ b/src/Makefile @@ -48,7 +48,10 @@ $(OBJECT_DIRS): # Extras Options # # with debug flags -.PHONY += debug run gdb pch clean docs +.PHONY += shader debug run gdb pch clean docs +shader: + sh ../compile.sh + debug: CXXFLAGS += -g # -DDEBUG debug: default diff --git a/src/main.cpp b/src/main.cpp index e8d392d..10aab26 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,30 +1,31 @@ -#include "main.hpp" - #include "shape.hpp" #include "vulkan_instance.hpp" #include "renderer2D.hpp" #include "renderer3D.hpp" +#include "vulkan_settings.hpp" #include #include #include -namespace gz::vk { +namespace gz::vlk { int mainLoop() { - LogCreateInfo logCI{}; - logCI.logfile = "main.log"; - logCI.storeLog = false; - logCI.prefix = "Main"; - logCI.prefixColor = Color::BG_RED; - logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; + LogCreateInfo logCI { + .logfile = "main.log", + .storeLog = false, + .prefix = "Main", + .prefixColor = Color::BG_RED, + .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR, + }; Log log(std::move(logCI)); - gz::SettingsManagerCreateInfo smCI{}; - smCI.filepath = gz::vk::CONFIG_FILE; - smCI.readFileOnCreation = true; - smCI.writeFileOnExit = true; - smCI.initialValues = gz::vk::INITIAL_SETTINGS; - smCI.throwExceptionWhenNewValueNotAllowed = true; + gz::SettingsManagerCreateInfo smCI { + .filepath = settings::CONFIG_FILE, + .initialValues = settings::INITIAL_SETTINGS, + .readFileOnCreation = true, + .writeFileOnExit = true, + .throwExceptionWhenNewValueNotAllowed = true, + }; VulkanInstance vulkanInstance(smCI); vulkanInstance.init(); @@ -90,5 +91,5 @@ namespace gz::vk { int main() { - return gz::vk::mainLoop(); + return gz::vlk::mainLoop(); } diff --git a/src/main.hpp b/src/main.hpp deleted file mode 100644 index d914d89..0000000 --- a/src/main.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - - -namespace gz::vk { - - - - - - - - - - - - - - -} // namespace gz::vk diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 6e91db5..7e53fdf 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -2,7 +2,7 @@ #include "vulkan_instance.hpp" -namespace gz::vk { +namespace gz::vlk { void Renderer::cleanup_(){ vk.destroyCommandBuffers(commandBuffers); diff --git a/src/renderer/renderer.hpp b/src/renderer/renderer.hpp index d4f22a6..1a6a3f6 100644 --- a/src/renderer/renderer.hpp +++ b/src/renderer/renderer.hpp @@ -1,16 +1,22 @@ #pragma once +#define VULKAN_HPP_NO_CONSTRUCTORS +#define VULKAN_HPP_NO_EXCEPTIONS +#include + // includes for child classes +#include "vulkan_util.hpp" +#include + #include "texture_manager.hpp" #include "vertex.hpp" #include "vulkan_allocator.hpp" -#include -#include + #include -namespace gz::vk { +namespace gz::vlk { /// Defined in texture_manager.hpp class TextureManager; /// Defined in vulkan_instance.hpp @@ -31,13 +37,13 @@ namespace gz::vk { VulkanInstance& vk; TextureManager& textureManager; - std::vector commandBuffers; + std::vector commandBuffers; /// On device local memory - VkBuffer vertexBuffer; + vk::Buffer vertexBuffer; MemoryInfo vertexBufferMemory; - VkDeviceSize vertexBufferSize; - VkBuffer indexBuffer; + vk::DeviceSize vertexBufferSize; + vk::Buffer indexBuffer; MemoryInfo indexBufferMemory; - VkDeviceSize indexBufferSize; + vk::DeviceSize indexBufferSize; }; // class RendererBase -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/renderer/renderer2D.cpp b/src/renderer/renderer2D.cpp index 25f9aa6..b1e4e52 100644 --- a/src/renderer/renderer2D.cpp +++ b/src/renderer/renderer2D.cpp @@ -1,17 +1,16 @@ #include "renderer2D.hpp" #include "exceptions.hpp" -#include "vk_enum_string.h" #include "vulkan_allocator.hpp" #include "vulkan_instance.hpp" #include "texture_manager.hpp" +#include #include +#include #include -#include - -namespace gz::vk { +namespace gz::vlk { // // INIT & CLEANUP @@ -19,12 +18,13 @@ namespace gz::vk { Renderer2D::Renderer2D(VulkanInstance& instance, TextureManager& textureManager) : Renderer(instance, textureManager) { - LogCreateInfo logCI{}; - logCI.logfile = "renderer2D.log"; - logCI.storeLog = false; - logCI.prefix = "2D-Renderer"; - logCI.prefixColor = Color::LI_MAGENTA; - logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; + LogCreateInfo logCI { + .logfile = "renderer2D.log", + .storeLog = false, + .prefix = "2D-Renderer", + .prefixColor = Color::LI_MAGENTA, + .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR, + }; rLog = Log(std::move(logCI)); vk.registerCleanupCallback(std::bind(&Renderer2D::cleanup, this)); @@ -59,8 +59,19 @@ namespace gz::vk { createRenderPass(); createImages(); vk.createFramebuffers(framebuffers, imageViews, renderPass); - std::vector descriptorSetLayouts = { textureManager.getDescriptorSetLayout() }; - vk.createGraphicsPipeline("shaders/vert2D.spv", "shaders/frag2D.spv", descriptorSetLayouts, false, renderPass, pipelines[PL_2D]); + std::vector descriptorSetLayouts = { textureManager.getDescriptorSetLayout() }; + + // specialization constant for sampler2D array length = atlas count + vk::SpecializationMapEntry specME { + .constantID = 0, + .offset = 0, + .size = sizeof(uint32_t), + }; + uint32_t atlasCount = textureManager.getAtlasCount(); + vk::SpecializationInfo specI; + specI.setData(atlasCount); + specI.setMapEntries(specME); + vk.createGraphicsPipeline("shaders/vert2D.spv", "shaders/frag2D.spv", descriptorSetLayouts, false, renderPass, pipelines[PL_2D], &specI); } @@ -74,7 +85,7 @@ namespace gz::vk { vk.destroyImageView(imageViews[i]); vk.destroyImage(images[i], imageMemory[i]); } - vkDestroyRenderPass(vk.getDevice(), renderPass, nullptr); + vk.getDevice().destroyRenderPass(renderPass, nullptr); } @@ -93,10 +104,10 @@ namespace gz::vk { images.resize(vk.getScImages().size()); imageMemory.resize(vk.getScImages().size()); imageViews.resize(vk.getScImages().size()); - VkImageUsageFlags usage= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + vk::ImageUsageFlags usage= vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc; for (size_t i = 0; i < images.size(); i++) { - vk.createImage(vk.getScExtent().width, vk.getScExtent().height, vk.getScImageFormat(), VK_IMAGE_TILING_OPTIMAL, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, images[i], imageMemory[i]); - vk.createImageView(vk.getScImageFormat(), images[i], imageViews[i], VK_IMAGE_ASPECT_COLOR_BIT); + vk.createImage(vk.getScExtent().width, vk.getScExtent().height, vk.getScImageFormat(), vk::ImageTiling::eOptimal, usage, vk::MemoryPropertyFlagBits::eDeviceLocal, images[i], imageMemory[i]); + vk.createImageView(vk.getScImageFormat(), images[i], imageViews[i], vk::ImageAspectFlagBits::eColor); } } @@ -104,87 +115,80 @@ namespace gz::vk { // RENDER PASS // void Renderer2D::createRenderPass() { - VkAttachmentDescription2 colorBlendAttachment{}; - colorBlendAttachment.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; - colorBlendAttachment.format = vk.getScImageFormat(); - colorBlendAttachment.samples = VK_SAMPLE_COUNT_1_BIT; - colorBlendAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - colorBlendAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - colorBlendAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - colorBlendAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - colorBlendAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - colorBlendAttachment.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + vk::AttachmentDescription2 colorBlendAttachment { + .format = vk.getScImageFormat(), + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eStore, + .stencilLoadOp = vk::AttachmentLoadOp::eDontCare, + .stencilStoreOp = vk::AttachmentStoreOp::eDontCare, + .initialLayout = vk::ImageLayout::eUndefined, + .finalLayout = vk::ImageLayout::eTransferSrcOptimal, + }; - VkAttachmentReference2 colorAttachmentRef{}; - colorAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2; - colorAttachmentRef.attachment = 0; - colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + vk::AttachmentReference2 colorAttachmentRef { + .attachment = 0, + .layout = vk::ImageLayout::eColorAttachmentOptimal, + }; - /* VkAttachmentDescription depthAttachment{}; */ + /* vk::AttachmentDescription depthAttachment { */ /* depthAttachment.format = findDepthFormat(); */ - /* depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; */ - /* depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; */ - /* depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */ - /* depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; */ - /* depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */ - /* depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; */ - /* depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */ + /* depthAttachment.samples = vk::SampleCountFlagBits::e1; */ + /* depthAttachment.loadOp = vk::AttachmentLoadOp::eClear; */ + /* depthAttachment.storeOp = vk::AttachmentStoreOp::eDontCare; */ + /* depthAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare; */ + /* depthAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare; */ + /* depthAttachment.initialLayout = vk::ImageLayout::eUndefined; */ + /* depthAttachment.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; */ - /* VkAttachmentReference depthAttachmentRef{}; */ + /* vk::AttachmentReference depthAttachmentRef { */ /* depthAttachmentRef.attachment = 1; */ - /* depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */ + /* depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; */ - VkSubpassDescription2 subpass{}; - subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; - /* subpass.pDepthStencilAttachment = &depthAttachmentRef; */ + vk::SubpassDescription2 subpass { + .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, + .colorAttachmentCount = 1, + .pColorAttachments = &colorAttachmentRef, + /* .pDepthStencilAttachment = &depthAttachmentRef, */ + }; - VkSubpassDependency2 colorAttachmentSD{}; - colorAttachmentSD.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2; - colorAttachmentSD.srcSubpass = VK_SUBPASS_EXTERNAL; - colorAttachmentSD.dstSubpass = 0; - colorAttachmentSD.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - colorAttachmentSD.srcAccessMask = 0; - colorAttachmentSD.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - colorAttachmentSD.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + vk::SubpassDependency2 colorAttachmentSD { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, + .dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, + .srcAccessMask = NO_ACC_FLAGS, + .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, + }; // dependecy for the image layout transition to transfer dst - VkSubpassDependency2 layoutTransitionSD{}; - layoutTransitionSD.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2; - layoutTransitionSD.srcSubpass = 0; - layoutTransitionSD.dstSubpass = VK_SUBPASS_EXTERNAL; - layoutTransitionSD.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - layoutTransitionSD.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; - layoutTransitionSD.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; - layoutTransitionSD.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT; - layoutTransitionSD.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - /* VkSubpassDependency dependency{}; */ + vk::SubpassDependency2 layoutTransitionSD { + .srcSubpass = 0, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, + .dstStageMask = vk::PipelineStageFlagBits::eTransfer, + .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, + .dstAccessMask = vk::AccessFlagBits::eTransferRead, + .dependencyFlags = vk::DependencyFlagBits::eByRegion, + }; + /* vk::SubpassDependency dependency { */ /* dependency.srcSubpass = VK_SUBPASS_EXTERNAL; */ /* dependency.dstSubpass = 0; */ - /* dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; */ + /* dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; */ /* dependency.srcAccessMask = 0; */ - /* dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; */ - /* dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; */ + /* dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; */ + /* dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite; */ - /* std::array attachments = { colorBlendAttachment, depthAttachment }; */ - std::vector attachments = { colorBlendAttachment }; - std::vector dependencies = { colorAttachmentSD, layoutTransitionSD }; - VkRenderPassCreateInfo2 renderPassCI{}; - renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2; - renderPassCI.attachmentCount = static_cast(attachments.size()); - renderPassCI.pAttachments = attachments.data(); - renderPassCI.subpassCount = 1; - renderPassCI.pSubpasses = &subpass; - renderPassCI.dependencyCount = dependencies.size(); - renderPassCI.pDependencies = dependencies.data(); - /* renderPassCI.dependencyCount = 0; */ - /* renderPassCI.pDependencies = nullptr; */ - /* renderPassCI.correlatedViewMaskCount = 0; */ - /* renderPassCI.pCorrelatedViewMasks = nullptr; */ - VkResult result = vkCreateRenderPass2(vk.getDevice(), &renderPassCI, nullptr, &renderPass); - if (result != VK_SUCCESS) { + /* std::array attachments = { colorBlendAttachment, depthAttachment }; */ + std::vector attachments = { colorBlendAttachment }; + std::vector dependencies = { colorAttachmentSD, layoutTransitionSD }; + vk::RenderPassCreateInfo2 renderPassCI; + renderPassCI.setDependencies(dependencies); + renderPassCI.setAttachments(attachments); + renderPassCI.setSubpasses(subpass); + + vk::Result result = vk.getDevice().createRenderPass2(&renderPassCI, nullptr, &renderPass); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Could not create render pass", "Renderer2D::createRenderPass"); } rLog("createRenderPass: Created render pass."); @@ -196,54 +200,55 @@ namespace gz::vk { // RENDERING // void Renderer2D::recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame) { - VkCommandBufferBeginInfo commandBufferBI{}; - commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - /* commandBufferBI.flags = 0; */ - /* commandBufferBI.pInheritanceInfo = nullptr; */ - VkResult result = vkBeginCommandBuffer(commandBuffers[currentFrame], &commandBufferBI); - if (result != VK_SUCCESS) { + vk::CommandBufferBeginInfo commandBufferBI { + /* .flags = 0, */ + /* .pInheritanceInfo = nullptr, */ + }; + vk::Result result = commandBuffers[currentFrame].begin(&commandBufferBI); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to begin 2D command buffer", "Renderer2D::recordCommandBuffer"); } - VkRenderPassBeginInfo renderPassBI{}; - renderPassBI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBI.renderPass = renderPass; - renderPassBI.framebuffer = framebuffers[imageIndex]; - renderPassBI.renderArea.offset = { 0, 0 }; - renderPassBI.renderArea.extent = vk.getScExtent(); // clear - std::array clearValues{}; - clearValues[0].color = {{1.0f, 0.0f, 0.0f, 1.0f}}; + std::array clearValues{}; + vk::ClearColorValue clearColor{}; + clearColor.setFloat32({ 0.0f, 0.0f, 0.1f, 0.5f }); + clearValues[0].setColor(std::move(clearColor)); /* clearValues[1].depthStencil = {1.0f, 0}; */ - renderPassBI.clearValueCount = static_cast(clearValues.size()); - renderPassBI.pClearValues = clearValues.data(); + vk::RenderPassBeginInfo renderPassBI { + .renderPass = renderPass, + .framebuffer = framebuffers[imageIndex], + .renderArea { .offset = { 0, 0 }, .extent = vk.getScExtent(), } + }; + renderPassBI.setClearValues(clearValues); - vkCmdBeginRenderPass(commandBuffers[currentFrame], &renderPassBI, VK_SUBPASS_CONTENTS_INLINE); + commandBuffers[currentFrame].beginRenderPass(&renderPassBI, vk::SubpassContents::eInline); - vkCmdBindPipeline(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[PL_2D].pipeline); - VkBuffer vertexBuffers[] = { vertexBuffer }; - VkDeviceSize offsets[] = {0}; + commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[PL_2D].pipeline); + vk::Buffer vertexBuffers[] = { vertexBuffer }; + vk::DeviceSize offsets[] = {0}; uint32_t bindingCount = 1; - vkCmdBindVertexBuffers(commandBuffers[currentFrame], BINDING, bindingCount, vertexBuffers, offsets); + uint32_t binding = 0; + commandBuffers[currentFrame].bindVertexBuffers(binding, bindingCount, vertexBuffers, offsets); // TODO use correct index type! - vkCmdBindIndexBuffer(commandBuffers[currentFrame], indexBuffer, NO_OFFSET, VK_INDEX_TYPE_UINT32); + commandBuffers[currentFrame].bindIndexBuffer(indexBuffer, NO_OFFSET, vk::IndexType::eUint32); uint32_t descriptorCount = 1; uint32_t firstSet = 0; uint32_t dynamicOffsetCount = 0; uint32_t* dynamicOffsets = nullptr; - vkCmdBindDescriptorSets(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[PL_2D].layout, firstSet, descriptorCount, &textureManager.getDescriptorSet(), dynamicOffsetCount, dynamicOffsets); + commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelines[PL_2D].layout, firstSet, descriptorCount, &textureManager.getDescriptorSet(), dynamicOffsetCount, dynamicOffsets); int instanceCount = 1; int firstIndex = 0; int firstInstance = 0; - vkCmdDrawIndexed(commandBuffers[currentFrame], static_cast(shapesIndicesCount), instanceCount, firstIndex, NO_OFFSET, firstInstance); - vkCmdEndRenderPass(commandBuffers[currentFrame]); + commandBuffers[currentFrame].drawIndexed(static_cast(shapesIndicesCount), instanceCount, firstIndex, NO_OFFSET, firstInstance); + commandBuffers[currentFrame].endRenderPass(); vk.copyImageToImage(commandBuffers[currentFrame], images[imageIndex], vk.getScImages()[imageIndex], vk.getScExtent()); - result = vkEndCommandBuffer(commandBuffers[currentFrame]); - if (result != VK_SUCCESS) { - rLog.error("Failed to record 2D - command buffer", "VkResult:", STR_VK_RESULT(result)); + result = commandBuffers[currentFrame].end(); + if (result != vk::Result::eSuccess) { + rLog.error("Failed to record 2D - command buffer", "VkResult:", result); throw getVkException(result, "Failed to record 2D - command buffer", "Renderer2D::recordCommandBufferWithTexture"); } vk.submitThisFrame(commandBuffers[currentFrame]); @@ -257,21 +262,24 @@ namespace gz::vk { } // create staging buffer - VkBuffer stagingBuffer; + vk::Buffer stagingBuffer; MemoryInfo stagingBufferMemory; - vk.createBuffer(vertexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); + vk.createBuffer(vertexBufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory); // fill staging buffer void* data; - vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, vertexBufferSize, NO_FLAGS, &data); + vk::Result result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, vertexBufferSize, NO_MEM_FLAGS, &data); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to map staging buffer", "Renderer3D::fillVertexBufferWithShapes"); + } Vertex2D* vdata = reinterpret_cast(data); size_t offset = 0; for (auto it = shapes.begin(); it != shapes.end(); it++) { - rLog("fillVertexBufferWithShapes: copying vertex buffer nr", it - shapes.begin(), "-", it->getVertices(), "to address:", long(vdata + offset), " offset:", offset); + rLog.log0("fillVertexBufferWithShapes: copying vertex buffer nr", it - shapes.begin(), "-", it->getVertices(), "to address:", long(vdata + offset), " offset:", offset); memcpy(vdata+offset, it->getVertices().data(), it->getVertices().size() * sizeof(Vertex2D)); offset += it->getVertices().size(); } - vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); + vk.getDevice().unmapMemory(stagingBufferMemory.memory); // fill vertex buffer vk.copyBuffer(stagingBuffer, vertexBuffer, vertexBufferSize); vk.destroyBuffer(stagingBuffer, stagingBufferMemory); @@ -283,13 +291,16 @@ namespace gz::vk { } // create staging buffer - VkBuffer stagingBuffer; + vk::Buffer stagingBuffer; MemoryInfo stagingBufferMemory; - vk.createBuffer(indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); + vk.createBuffer(indexBufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory); // fill staging buffer void* data; - vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, indexBufferSize, NO_FLAGS, &data); + vk::Result result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, indexBufferSize, NO_MEM_FLAGS, &data); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to map staging buffer", "Renderer2D::fillIndexBufferWithShapes"); + } uint32_t* idata = reinterpret_cast(data); size_t offset = 0; for (auto it = shapes.begin(); it != shapes.end(); it++) { @@ -297,8 +308,8 @@ namespace gz::vk { memcpy(idata+offset, it->getIndices().data(), it->getIndices().size() * sizeof(uint32_t)); offset += it->getIndices().size(); } - rLog("fillIndexBufferWithShapes: indices count:", shapesIndicesCount); - vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); + rLog.log0("fillIndexBufferWithShapes: indices count:", shapesIndicesCount); + vk.getDevice().unmapMemory(stagingBufferMemory.memory); // fill index buffer vk.copyBuffer(stagingBuffer, indexBuffer, indexBufferSize); @@ -320,11 +331,11 @@ namespace gz::vk { void Renderer2D::drawFrame(uint32_t imageIndex) { - vkResetCommandBuffer(commandBuffers[vk.getCurrentFrame()], NO_FLAGS); + commandBuffers[vk.getCurrentFrame()].reset(); /* recordCommandBuffer(imageIndex, vk.getCurrentFrame()); */ recordCommandBuffer(imageIndex, vk.getCurrentFrame()); } -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/renderer/renderer2D.hpp b/src/renderer/renderer2D.hpp index 0fc283f..f63b931 100644 --- a/src/renderer/renderer2D.hpp +++ b/src/renderer/renderer2D.hpp @@ -6,7 +6,7 @@ #include "vulkan_allocator.hpp" #include "vulkan_util.hpp" -namespace gz::vk { +namespace gz::vlk { class Renderer2D : public Renderer { public: /** @@ -49,13 +49,13 @@ namespace gz::vk { * @details * As of now, this does (in the same command buffer from graphicsPool) * -# begin render pass - * - image layout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + * - image layout: vk::ImageLayout::eColorAttachmentOptimal * - clear image * -# bind 2d pipeline, vertex and index buffer * -# bind texture sampler * -# draw indexed: draw the shapes from shapes vector * -# end render pass - * - image layout: VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + * - image layout: vk::ImageLayout::eTransferSrcOptimal * -# copy image to swapChain image with same imageIndex */ void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame); @@ -67,9 +67,9 @@ namespace gz::vk { * The images are used as render targets. After rendering, the current image gets blitted onto the current swap chain image. * @{ */ - std::vector images; + std::vector images; std::vector imageMemory; - std::vector imageViews; + std::vector imageViews; /** * @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images */ @@ -81,10 +81,10 @@ namespace gz::vk { * @details * Attachments: * - color blend: - * - loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR - * - storeOp = VK_ATTACHMENT_STORE_OP_STORE - * - initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL - * - finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + * - loadOp = vk::AttachmentLoadOp::eClear + * - storeOp = vk::AttachmentStoreOp::eStore + * - initialLayout = vk::ImageLayout::eColorAttachmentOptimal + * - finalLayout = vk::ImageLayout::eColorAttachmentOptimal * - stencil load/store = dont care */ /// @{ @@ -92,10 +92,10 @@ namespace gz::vk { * @brief Create a render pass */ void createRenderPass(); - VkRenderPass renderPass; + vk::RenderPass renderPass; /// @} - std::vector framebuffers; + std::vector framebuffers; // PIPELINE PipelineContainer pipelines; @@ -130,4 +130,4 @@ namespace gz::vk { Log rLog; }; -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/renderer/renderer3D.cpp b/src/renderer/renderer3D.cpp index ca3622a..a02ded1 100644 --- a/src/renderer/renderer3D.cpp +++ b/src/renderer/renderer3D.cpp @@ -6,23 +6,24 @@ #include "texture_manager.hpp" #include "exceptions.hpp" #include "vk_enum_string.h" +#include "vulkan_settings.hpp" #include -#include #include -namespace gz::vk { +namespace gz::vlk { // // INIT & CLEANUP // Renderer3D::Renderer3D(VulkanInstance& instance, TextureManager& textureManager) : Renderer(instance, textureManager) { - LogCreateInfo logCI{}; - logCI.logfile = "renderer3D.log"; - logCI.storeLog = false; - logCI.prefix = "3D-Renderer"; - logCI.prefixColor = Color::LI_CYAN; - logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; + LogCreateInfo logCI{ + .logfile = "renderer3D.log", + .storeLog = false, + .prefix = "3D-Renderer", + .prefixColor = Color::LI_CYAN, + .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR, + }; rLog = Log(std::move(logCI)); vk.registerCleanupCallback(std::bind(&Renderer3D::cleanup, this)); @@ -33,7 +34,6 @@ namespace gz::vk { const size_t indexCount = 10000; vk.createVertexBuffer(vertexCount, vertexBuffer, vertexBufferMemory, vertexBufferSize); vk.createIndexBuffer(indexCount, indexBuffer, indexBufferMemory, indexBufferSize); - rLog("Created Renderer3D"); // TODO loadModel(); @@ -46,7 +46,7 @@ namespace gz::vk { &descriptorSetLayout, &descriptorPool, }, { &framebuffers, &images, &imageMemory, &imageViews, &commandBuffers, &descriptorSets })); - rLog("Created Renderer3D"); + rLog.log1("Created Renderer3D"); } void Renderer3D::cleanup() { @@ -55,8 +55,8 @@ namespace gz::vk { for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) { vk.destroyBuffer(uniformBuffers[i], uniformBuffersMemory[i]); } - vkDestroyDescriptorSetLayout(vk.getDevice(), descriptorSetLayout, NO_ALLOC); - vkDestroyDescriptorPool(vk.getDevice(), descriptorPool, NO_ALLOC); + vk.getDevice().destroyDescriptorSetLayout(descriptorSetLayout, NO_ALLOC); + vk.getDevice().destroyDescriptorPool(descriptorPool, NO_ALLOC); cleanupSwapChainDependantResources(); cleanup_(); @@ -67,11 +67,13 @@ namespace gz::vk { // SWAPCHAIN DEPENDANT // void Renderer3D::initSwapChainDependantResources() { + // UPDATE DOC ON CHANGES! createRenderPass(); createImages(); - vk.createFramebuffers(framebuffers, imageViews, renderPass); - std::vector descriptorSetLayouts = { descriptorSetLayout }; - vk.createGraphicsPipeline("shaders/vert.spv", "shaders/frag.spv", descriptorSetLayouts, false, renderPass, pipelines[PL_3D]); + createDepthImage(); + vk.createFramebuffers(framebuffers, imageViews, renderPass, depthImageView); + std::vector descriptorSetLayouts = { descriptorSetLayout }; + vk.createGraphicsPipeline("shaders/vert.spv", "shaders/frag.spv", descriptorSetLayouts, true, renderPass, pipelines[PL_3D]); } @@ -81,13 +83,14 @@ namespace gz::vk { vk.destroyFramebuffers(framebuffers); + vk.destroyImageView(depthImageView); + vk.destroyImage(depthImage, depthImageMemory); + for (size_t i = 0; i < images.size(); i++) { vk.destroyImageView(imageViews[i]); vk.destroyImage(images[i], imageMemory[i]); } - vkDestroyRenderPass(vk.getDevice(), renderPass, nullptr); - - + vk.getDevice().destroyRenderPass(renderPass, nullptr); } @@ -104,99 +107,120 @@ namespace gz::vk { images.resize(vk.getScImages().size()); imageMemory.resize(vk.getScImages().size()); imageViews.resize(vk.getScImages().size()); - VkImageUsageFlags usage= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + vk::ImageUsageFlags usage= vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc; for (size_t i = 0; i < images.size(); i++) { - vk.createImage(vk.getScExtent().width, vk.getScExtent().height, vk.getScImageFormat(), VK_IMAGE_TILING_OPTIMAL, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, images[i], imageMemory[i]); - vk.createImageView(vk.getScImageFormat(), images[i], imageViews[i], VK_IMAGE_ASPECT_COLOR_BIT); + vk.createImage(vk.getScExtent().width, vk.getScExtent().height, vk.getScImageFormat(), vk::ImageTiling::eOptimal, usage, vk::MemoryPropertyFlagBits::eDeviceLocal, images[i], imageMemory[i]); + vk.createImageView(vk.getScImageFormat(), images[i], imageViews[i], vk::ImageAspectFlagBits::eColor); } } +// +// DEPTH +// + void Renderer3D::createDepthImage() { + vk::MemoryPropertyFlags memoryProperties = vk::MemoryPropertyFlagBits::eDeviceLocal; + vk::ImageUsageFlags imageUsage = vk::ImageUsageFlagBits::eDepthStencilAttachment; + vk::ImageTiling tiling = vk::ImageTiling::eOptimal; + vk::Format depthFormat = vk.getDepthFormat(); + + vk.createImage(vk.getScExtent().width, vk.getScExtent().height, depthFormat, tiling, imageUsage, memoryProperties, depthImage, depthImageMemory); + vk.createImageView(depthFormat, depthImage, depthImageView, vk::ImageAspectFlagBits::eDepth); + + vk.transitionImageLayout(depthImage, depthFormat, vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthStencilAttachmentOptimal); + } + // // RENDER PASS // void Renderer3D::createRenderPass() { - VkAttachmentDescription2 colorBlendAttachment{}; - colorBlendAttachment.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; - colorBlendAttachment.format = vk.getScImageFormat(); - colorBlendAttachment.samples = VK_SAMPLE_COUNT_1_BIT; - colorBlendAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - colorBlendAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - colorBlendAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - colorBlendAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - colorBlendAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - colorBlendAttachment.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + vk::AttachmentDescription2 colorBlendAD { + .format = vk.getScImageFormat(), + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eStore, + .stencilLoadOp = vk::AttachmentLoadOp::eDontCare, + .stencilStoreOp = vk::AttachmentStoreOp::eDontCare, + .initialLayout = vk::ImageLayout::eUndefined, + .finalLayout = vk::ImageLayout::eTransferSrcOptimal, + }; - VkAttachmentReference2 colorAttachmentRef{}; - colorAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2; - colorAttachmentRef.attachment = 0; - colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + vk::AttachmentReference2 colorBlendAR { + .attachment = 0, + .layout = vk::ImageLayout::eColorAttachmentOptimal, + }; - /* VkAttachmentDescription depthAttachment{}; */ - /* depthAttachment.format = findDepthFormat(); */ - /* depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; */ - /* depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; */ - /* depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */ - /* depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; */ - /* depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */ - /* depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; */ - /* depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */ + vk::AttachmentDescription2 depthAD { + .format = vk.getDepthFormat(), + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eDontCare, + .stencilLoadOp = vk::AttachmentLoadOp::eDontCare, + .stencilStoreOp = vk::AttachmentStoreOp::eDontCare, + .initialLayout = vk::ImageLayout::eUndefined, + .finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal, + }; - /* VkAttachmentReference depthAttachmentRef{}; */ - /* depthAttachmentRef.attachment = 1; */ - /* depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */ + vk::AttachmentReference2 depthAR { + .attachment = 1, + .layout = vk::ImageLayout::eDepthStencilAttachmentOptimal, + }; - VkSubpassDescription2 subpass{}; - subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; - /* subpass.pDepthStencilAttachment = &depthAttachmentRef; */ + vk::SubpassDescription2 subpass { + .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, + .colorAttachmentCount = 1, + .pColorAttachments = &colorBlendAR, + .pDepthStencilAttachment = &depthAR, + }; - VkSubpassDependency2 colorAttachmentSD{}; - colorAttachmentSD.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2; - colorAttachmentSD.srcSubpass = VK_SUBPASS_EXTERNAL; - colorAttachmentSD.dstSubpass = 0; - colorAttachmentSD.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - colorAttachmentSD.srcAccessMask = 0; - colorAttachmentSD.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - colorAttachmentSD.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + // wait until image is available + vk::SubpassDependency2 colorAttachmentSD { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests, + .dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests, + .srcAccessMask = NO_ACC_FLAGS, + .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite, + }; - // dependecy for the image layout transition to transfer dst - VkSubpassDependency2 layoutTransitionSD{}; - layoutTransitionSD.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2; - layoutTransitionSD.srcSubpass = 0; - layoutTransitionSD.dstSubpass = VK_SUBPASS_EXTERNAL; - layoutTransitionSD.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; - layoutTransitionSD.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; - layoutTransitionSD.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; - layoutTransitionSD.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT; - layoutTransitionSD.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - VkSubpassDependency dependency{}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.srcAccessMask = 0; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + // image layout transition to transfer dst + vk::SubpassDependency2 layoutTransitionSD { + .srcSubpass = 0, + .dstSubpass = VK_SUBPASS_EXTERNAL, + .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, + .dstStageMask = vk::PipelineStageFlagBits::eTransfer, + .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, + .dstAccessMask = vk::AccessFlagBits::eTransferRead, + .dependencyFlags = vk::DependencyFlagBits::eByRegion, + }; - /* std::array attachments = { colorBlendAttachment, depthAttachment }; */ - std::vector attachments = { colorBlendAttachment }; - std::vector dependencies = { colorAttachmentSD, layoutTransitionSD }; - VkRenderPassCreateInfo2 renderPassCI{}; - renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2; - renderPassCI.attachmentCount = static_cast(attachments.size()); - renderPassCI.pAttachments = attachments.data(); - renderPassCI.subpassCount = 1; - renderPassCI.pSubpasses = &subpass; - renderPassCI.dependencyCount = dependencies.size(); - renderPassCI.pDependencies = dependencies.data(); - /* renderPassCI.dependencyCount = 0; */ - /* renderPassCI.pDependencies = nullptr; */ - /* renderPassCI.correlatedViewMaskCount = 0; */ - /* renderPassCI.pCorrelatedViewMasks = nullptr; */ - VkResult result = vkCreateRenderPass2(vk.getDevice(), &renderPassCI, nullptr, &renderPass); - if (result != VK_SUCCESS) { + /* vk::SubpassDependency2 dependency { */ + /* dependency.srcSubpass = VK_SUBPASS_EXTERNAL; */ + /* dependency.dstSubpass = 0; */ + /* dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; */ + /* dependency.srcAccessMask = 0; */ + /* dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; */ + /* dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite; */ + + std::vector attachments = { colorBlendAD, depthAD, }; + std::vector dependencies = { colorAttachmentSD, layoutTransitionSD }; + vk::RenderPassCreateInfo2 renderPassCI { + /* .attachmentCount = static_cast(attachments.size()), */ + /* .pAttachments = attachments.data(), */ + /* .subpassCount = 1, */ + /* .pSubpasses = &subpass, */ + /* .dependencyCount = static_cast(dependencies.size()), */ + /* .pDependencies = dependencies.data(), */ + /* .dependencyCount = 0, */ + /* .pDependencies = nullptr, */ + /* .correlatedViewMaskCount = 0, */ + /* .pCorrelatedViewMasks = nullptr, */ + }; + renderPassCI.setAttachments(attachments); + renderPassCI.setDependencies(dependencies); + renderPassCI.setSubpasses(subpass); + vk::Result result = vk.getDevice().createRenderPass2(&renderPassCI, nullptr, &renderPass); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Could not create render pass", "Renderer3D::createRenderPass"); } rLog.log0("createRenderPass: Created render pass."); @@ -210,91 +234,90 @@ namespace gz::vk { void Renderer3D::createDescriptorResources() { // LAYOUT // 1) uniform buffer object - VkDescriptorSetLayoutBinding uboLayoutBinding{}; - uboLayoutBinding.binding = 0; - uboLayoutBinding.descriptorCount = 1; - uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - /* uboLayoutBinding.pImmutableSamplers = nullptr; */ + vk::DescriptorSetLayoutBinding uboLayoutBinding { + .binding = 0, + .descriptorType = vk::DescriptorType::eUniformBuffer, + .descriptorCount = 1, + .stageFlags = vk::ShaderStageFlagBits::eVertex, + /* .pImmutableSamplers = nullptr, */ + }; // 2) combined image sampler - VkDescriptorSetLayoutBinding samplerLayoutBinding{}; - samplerLayoutBinding.binding = 1; - samplerLayoutBinding.descriptorCount = 1; - samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - /* samplerLayoutBinding.pImmutableSamplers = nullptr; */ + vk::DescriptorSetLayoutBinding samplerLayoutBinding { + .binding = 1, + .descriptorType = vk::DescriptorType::eCombinedImageSampler, + .descriptorCount = 1, + .stageFlags = vk::ShaderStageFlagBits::eFragment, + /* .pImmutableSamplers = nullptr, */ + }; - std::vector bindings = { uboLayoutBinding, samplerLayoutBinding }; + std::vector bindings = { uboLayoutBinding, samplerLayoutBinding }; vk.createDescriptorSetLayout(bindings, descriptorSetLayout); // POOL - std::array poolSizes; - poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + std::array poolSizes; + poolSizes[0].type = vk::DescriptorType::eUniformBuffer; poolSizes[0].descriptorCount = static_cast(vk.getMaxFramesInFlight()); - poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSizes[1].type = vk::DescriptorType::eCombinedImageSampler; poolSizes[1].descriptorCount = static_cast(vk.getMaxFramesInFlight()); - VkDescriptorPoolCreateInfo poolCI{}; - poolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolCI.poolSizeCount = static_cast(poolSizes.size()); - poolCI.pPoolSizes = poolSizes.data(); - poolCI.maxSets = static_cast(vk.getMaxFramesInFlight()); - VkResult result = vkCreateDescriptorPool(vk.getDevice(), &poolCI, nullptr, &descriptorPool); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create descriptor pool", "Renderer3D::createDescriptorResources"); - } + vk::DescriptorPoolCreateInfo poolCI { + .maxSets = static_cast(vk.getMaxFramesInFlight()), + }; + poolCI.setPoolSizes(poolSizes); + + vk::Result result; + std::tie(result, descriptorPool) = vk.getDevice().createDescriptorPool(poolCI); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create descriptor pool", "Renderer3D::createDescriptorResources"); + } // SETS - std::vector layouts(vk.getMaxFramesInFlight(), descriptorSetLayout); - VkDescriptorSetAllocateInfo setAI{}; - setAI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - setAI.descriptorPool = descriptorPool; - setAI.descriptorSetCount = static_cast(layouts.size()); - setAI.pSetLayouts = layouts.data(); + std::vector layouts(vk.getMaxFramesInFlight(), descriptorSetLayout); + vk::DescriptorSetAllocateInfo setAI { + .descriptorPool = descriptorPool, + }; + setAI.setSetLayouts(layouts); - descriptorSets.resize(vk.getMaxFramesInFlight()); - result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, descriptorSets.data()); - if (result != VK_SUCCESS) { + // TODO is resize needed? + /* descriptorSets.resize(vk.getMaxFramesInFlight()); */ + std::tie(result, descriptorSets) = vk.getDevice().allocateDescriptorSets(setAI); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to create descriptor sets", "Renderer3D::createDescriptorResources"); } // configure sets for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) { - VkDescriptorBufferInfo bufferI{}; - bufferI.buffer = uniformBuffers[i]; - bufferI.offset = 0; - bufferI.range = VK_WHOLE_SIZE; // sizeof(UniformBufferObject); + vk::DescriptorBufferInfo bufferI { + .buffer = uniformBuffers[i], + .offset = 0, + .range = VK_WHOLE_SIZE, // sizeof(UniformBufferObject), + }; - VkDescriptorImageInfo imageI{}; - imageI.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageI.imageView = textureManager.getTextureAtlas().getTextureImageView(); - imageI.sampler = textureManager.getTextureAtlas().getTextureSampler(); + vk::DescriptorImageInfo imageI { + .sampler = textureManager.getTextureAtlas().getTextureSampler(), + .imageView = textureManager.getTextureAtlas().getTextureImageView(), + .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal, + }; - std::array descriptorW{}; - descriptorW[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + std::array descriptorW{}; descriptorW[0].dstSet = descriptorSets[i]; descriptorW[0].dstBinding = bindingUniformBuffer; descriptorW[0].dstArrayElement = 0; - descriptorW[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptorW[0].descriptorCount = 1; - descriptorW[0].pBufferInfo = &bufferI; + descriptorW[0].descriptorType = vk::DescriptorType::eUniformBuffer; + descriptorW[0].setBufferInfo(bufferI); /* descriptorW[0].pImageInfo = nullptr; */ /* descriptorW[0].pTexelBufferView = nullptr; */ - descriptorW[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorW[1].dstSet = descriptorSets[i]; descriptorW[1].dstBinding = bindingCombinedImageSampler; descriptorW[1].dstArrayElement = 0; - descriptorW[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorW[1].descriptorCount = 1; - /* descriptorW[1].pBufferInfo = &bufferI; */ - descriptorW[1].pImageInfo = &imageI; + descriptorW[1].descriptorType = vk::DescriptorType::eCombinedImageSampler; + descriptorW[1].setImageInfo(imageI); /* descriptorW[1].pTexelBufferView = nullptr; */ - uint32_t descriptorWriteCount = static_cast(descriptorW.size()); - uint32_t descriptorCopyCount = 0; - vkUpdateDescriptorSets(vk.getDevice(), descriptorWriteCount, descriptorW.data(), descriptorCopyCount, nullptr); + // write 1, copy 0 + vk.getDevice().updateDescriptorSets(descriptorW, nullptr); } rLog.log0("createDescriptorResources: Created descriptor layouts, pool and sets."); } @@ -305,10 +328,10 @@ namespace gz::vk { void Renderer3D::loadModel() { // load model into VerticesAndIndices struct rLog.log1("Renderer3D: loadModel: loading model"); - vk.loadModel(model); + vk.loadModel(settings::MODEL_PATH, model); // TODO use correct type - VkDeviceSize requiredVertexBufferSize = model.vertices.size() * sizeof(Vertex3D); - VkDeviceSize requiredIndexBufferSize = model.indices.size() * sizeof(uint32_t); + vk::DeviceSize requiredVertexBufferSize = model.vertices.size() * sizeof(Vertex3D); + vk::DeviceSize requiredIndexBufferSize = model.indices.size() * sizeof(uint32_t); if (requiredVertexBufferSize > vertexBufferSize) { throw VkException("Renderer3D::loadModel: vertex buffer too small"); } if (requiredIndexBufferSize > indexBufferSize) { throw VkException("Renderer3D::loadModel: index buffer too small"); } @@ -316,14 +339,18 @@ namespace gz::vk { rLog.log0("Renderer3D: loadModel: filling vertex buffer"); // copy to vertexBuffer // create staging buffer - VkBuffer stagingBuffer; + vk::Buffer stagingBuffer; MemoryInfo stagingBufferMemory; - vk.createBuffer(requiredVertexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); + vk.createBuffer(requiredVertexBufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory); // fill staging buffer void* data; - vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, requiredVertexBufferSize, NO_FLAGS, &data); + vk::Result result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, requiredVertexBufferSize, NO_MEM_FLAGS, &data); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to map staging buffer for vertices", "Renderer3D::loadModel"); + } + memcpy(data, model.vertices.data(), requiredVertexBufferSize); - vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); + vk.getDevice().unmapMemory(stagingBufferMemory.memory); // fill vertex buffer vk.copyBuffer(stagingBuffer, vertexBuffer, requiredVertexBufferSize); vk.destroyBuffer(stagingBuffer, stagingBufferMemory); @@ -331,11 +358,14 @@ namespace gz::vk { rLog.log0("Renderer3D: loadModel: filling index buffer"); data = nullptr; // copy to index buffer - vk.createBuffer(requiredIndexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); + vk.createBuffer(requiredIndexBufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory); // fill staging buffer - vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, requiredIndexBufferSize, NO_FLAGS, &data); + result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, requiredIndexBufferSize, NO_MEM_FLAGS, &data); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to map staging buffer for indices", "Renderer3D::loadModel"); + } memcpy(data, model.indices.data(), requiredIndexBufferSize); - vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); + vk.getDevice().unmapMemory(stagingBufferMemory.memory); // fill index buffer vk.copyBuffer(stagingBuffer, indexBuffer, requiredIndexBufferSize); vk.destroyBuffer(stagingBuffer, stagingBufferMemory); @@ -345,54 +375,50 @@ namespace gz::vk { // RENDERING // void Renderer3D::recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame) { - VkCommandBufferBeginInfo commandBufferBI{}; - commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - commandBufferBI.flags = 0; - commandBufferBI.pInheritanceInfo = nullptr; - VkResult result = vkBeginCommandBuffer(commandBuffers[currentFrame], &commandBufferBI); - if (result != VK_SUCCESS) { + vk::CommandBufferBeginInfo commandBufferBI; + vk::Result result = commandBuffers[currentFrame].begin(commandBufferBI); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to begin 3D command buffer", "Renderer3D::recordCommandBuffer"); } - VkRenderPassBeginInfo renderPassBI{}; - renderPassBI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBI.renderPass = renderPass; - renderPassBI.framebuffer = framebuffers[imageIndex]; - renderPassBI.renderArea.offset = { 0, 0 }; - renderPassBI.renderArea.extent = vk.getScExtent(); // clear - std::array clearValues{}; - clearValues[0].color = {{1.0f, 0.0f, 0.0f, 1.0f}}; - /* clearValues[1].depthStencil = {1.0f, 0}; */ - renderPassBI.clearValueCount = static_cast(clearValues.size()); - renderPassBI.pClearValues = clearValues.data(); + std::array clearValues{}; + vk::ClearColorValue clearColor{}; + clearColor.setFloat32({0.1f, 0.0f, 0.0f, 0.5f}); + clearValues[0].setColor(std::move(clearColor)); + clearValues[1].setDepthStencil({1.0f, 0}); - vkCmdBeginRenderPass(commandBuffers[currentFrame], &renderPassBI, VK_SUBPASS_CONTENTS_INLINE); + vk::RenderPassBeginInfo renderPassBI { + .renderPass = renderPass, + .framebuffer = framebuffers[imageIndex], + .renderArea { .offset = { 0, 0 }, .extent = vk.getScExtent() } + }; + renderPassBI.setClearValues(clearValues); - vkCmdBindPipeline(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[PL_3D].pipeline); - VkBuffer vertexBuffers[] = { vertexBuffer }; - VkDeviceSize offsets[] = {0}; + commandBuffers[currentFrame].beginRenderPass(renderPassBI, vk::SubpassContents::eInline); + + commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[PL_3D].pipeline); + vk::Buffer vertexBuffers[] = { vertexBuffer }; + vk::DeviceSize offsets[] = {0}; uint32_t bindingCount = 1; - vkCmdBindVertexBuffers(commandBuffers[currentFrame], BINDING, bindingCount, vertexBuffers, offsets); + uint32_t firstBinding = 0; + commandBuffers[currentFrame].bindVertexBuffers(firstBinding, bindingCount, vertexBuffers, offsets); // TODO use correct index type! - vkCmdBindIndexBuffer(commandBuffers[currentFrame], indexBuffer, NO_OFFSET, VK_INDEX_TYPE_UINT32); + commandBuffers[currentFrame].bindIndexBuffer(indexBuffer, NO_OFFSET, vk::IndexType::eUint32); - uint32_t descriptorCount = 1; uint32_t firstSet = 0; - uint32_t dynamicOffsetCount = 0; - uint32_t* dynamicOffsets = nullptr; - vkCmdBindDescriptorSets(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[PL_3D].layout, firstSet, descriptorCount, &descriptorSets[currentFrame], dynamicOffsetCount, dynamicOffsets); + commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelines[PL_3D].layout, firstSet, descriptorSets[currentFrame], {}); int instanceCount = 1; int firstIndex = 0; int firstInstance = 0; - vkCmdDrawIndexed(commandBuffers[currentFrame], static_cast(model.indices.size()), instanceCount, firstIndex, NO_OFFSET, firstInstance); - vkCmdEndRenderPass(commandBuffers[currentFrame]); + commandBuffers[currentFrame].drawIndexed(static_cast(model.indices.size()), instanceCount, firstIndex, NO_OFFSET, firstInstance); + commandBuffers[currentFrame].endRenderPass(); vk.copyImageToImage(commandBuffers[currentFrame], images[imageIndex], vk.getScImages()[imageIndex], vk.getScExtent()); - result = vkEndCommandBuffer(commandBuffers[currentFrame]); - if (result != VK_SUCCESS) { - rLog.error("Failed to record 3D - command buffer", "VkResult:", STR_VK_RESULT(result)); + result = commandBuffers[currentFrame].end(); + if (result != vk::Result::eSuccess) { + rLog.error("Failed to record 3D - command buffer", "VkResult:", result); throw getVkException(result, "Failed to record 3D - command buffer", "Renderer3D::recordCommandBuffer"); } vk.submitThisFrame(commandBuffers[currentFrame]); @@ -401,7 +427,7 @@ namespace gz::vk { // RENDERING // void Renderer3D::drawFrame(uint32_t imageIndex) { - vkResetCommandBuffer(commandBuffers[vk.getCurrentFrame()], NO_FLAGS); + commandBuffers[vk.getCurrentFrame()].reset(NO_CMD_RESET_FLAGS); /* recordCommandBuffer(imageIndex, vk.getCurrentFrame()); */ updateUniformBuffer(); recordCommandBuffer(imageIndex, vk.getCurrentFrame()); @@ -409,13 +435,13 @@ namespace gz::vk { void Renderer3D::createUniformBuffers() { - VkDeviceSize bufferSize = sizeof(UniformBufferObject); + vk::DeviceSize bufferSize = sizeof(UniformBufferObject); uniformBuffers.resize(vk.getMaxFramesInFlight()); uniformBuffersMemory.resize(vk.getMaxFramesInFlight()); for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) { - vk.createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]); + vk.createBuffer(bufferSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, uniformBuffers[i], uniformBuffersMemory[i]); } } @@ -436,9 +462,12 @@ namespace gz::vk { /* ubo.projection[1][1] *= -1; // y coordinate inverted in opengl */ MemoryInfo& uniformBufferMI = uniformBuffersMemory[vk.getCurrentFrame()]; void* data; - vkMapMemory(vk.getDevice(), uniformBufferMI.memory, uniformBufferMI.offset, sizeof(ubo), NO_FLAGS, &data); + vk::Result result = vk.getDevice().mapMemory(uniformBufferMI.memory, uniformBufferMI.offset, sizeof(ubo), NO_MEM_FLAGS, &data); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to map staging buffer", "Renderer3D::updateUniformBuffer"); + } memcpy(data, &ubo, sizeof(ubo)); - vkUnmapMemory(vk.getDevice(), uniformBufferMI.memory); + vk.getDevice().unmapMemory(uniformBufferMI.memory); } @@ -446,4 +475,4 @@ namespace gz::vk { -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/renderer/renderer3D.hpp b/src/renderer/renderer3D.hpp index 3f66c68..07f6df8 100644 --- a/src/renderer/renderer3D.hpp +++ b/src/renderer/renderer3D.hpp @@ -5,7 +5,7 @@ #include "vulkan_allocator.hpp" #include "vulkan_util.hpp" -namespace gz::vk { +namespace gz::vlk { struct UniformBufferObject { alignas(16) glm::mat4 model; alignas(16) glm::mat4 view; @@ -34,7 +34,7 @@ namespace gz::vk { /// @} private: void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame); - std::vector uniformBuffers; + std::vector uniformBuffers; std::vector uniformBuffersMemory; void createUniformBuffers(); void updateUniformBuffer(); @@ -45,24 +45,36 @@ namespace gz::vk { * The images are used as render targets. After rendering, the current image gets blitted onto the current swap chain image. */ /// @{ - std::vector images; + std::vector images; std::vector imageMemory; - std::vector imageViews; + std::vector imageViews; /** * @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images */ void createImages(); /// @} + /** + * @name Depth + */ + /// @{ + vk::Image depthImage; + MemoryInfo depthImageMemory; + vk::ImageView depthImageView; + /** + * @brief Create depth image and view with a @ref VulkanInstance::getDepthFormat() "depth format" + */ + void createDepthImage(); + /// @} /** * @name Render pass * @details * Attachments: * - color blend: - * - loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR - * - storeOp = VK_ATTACHMENT_STORE_OP_STORE - * - initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL - * - finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + * - loadOp = vk::AttachmentLoadOp::eClear + * - storeOp = vk::AttachmentStoreOp::eStore + * - initialLayout = vk::ImageLayout::eColorAttachmentOptimal + * - finalLayout = vk::ImageLayout::eColorAttachmentOptimal * - stencil load/store = dont care */ /// @{ @@ -70,10 +82,10 @@ namespace gz::vk { * @brief Create a render pass */ void createRenderPass(); - VkRenderPass renderPass; + vk::RenderPass renderPass; /// @} - std::vector framebuffers; + std::vector framebuffers; // PIPELINE PipelineContainer pipelines; @@ -84,9 +96,9 @@ namespace gz::vk { * -# Combined Image Sampler (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) */ /// @{ - VkDescriptorPool descriptorPool; - VkDescriptorSetLayout descriptorSetLayout; - std::vector descriptorSets; + vk::DescriptorPool descriptorPool; + vk::DescriptorSetLayout descriptorSetLayout; + std::vector descriptorSets; /** * @brief Create a descriptor layout binding for the MVP uniform buffer object * @details Create a desciptor set layout with bindings for @@ -116,10 +128,11 @@ namespace gz::vk { /** * @brief Sets up resources that depend on the swap chain or its attributes * @details - * Initializes up: - * - images, imageMemory, imageViews - * - framebuffers - * - render pass + * Initializes: + * - @ref createRenderPass() "render pass" + * - @ref createImages() "images and imageViews" + * - @ref createDepthImage() "depth image and view" + * - @ref VulkanInstance::createFramebuffers() "framebuffers" * - pipeline */ void initSwapChainDependantResources(); diff --git a/src/shader/shader.frag b/src/shader/shader.frag deleted file mode 100644 index 6bf4554..0000000 --- a/src/shader/shader.frag +++ /dev/null @@ -1,16 +0,0 @@ -#version 450 -#extension GL_EXT_debug_printf : enable - -layout(binding = 1) uniform sampler2D textureSampler; - -layout(location = 0) in vec3 fragColor; -layout(location = 1) in vec2 fragTextureCoordinate; - -layout(location = 0) out vec4 outColor; - -void main() { - /* outColor = vec4(fragColor, 1.0); */ - /* debugPrintfEXT("outColor %v3f", fragColor); */ - outColor = vec4(fragTextureCoordinate, 0.0, 1.0); - /* outColor = vec4(fragColor * texture(textureSampler, fragTextureCoordinate).rgb, 1.0); */ -} diff --git a/src/shader/shader.vert b/src/shader/shader.vert deleted file mode 100644 index 351875e..0000000 --- a/src/shader/shader.vert +++ /dev/null @@ -1,25 +0,0 @@ -#version 450 -#extension GL_EXT_debug_printf : enable - -layout(binding = 0) uniform UniformBufferObject { - mat4 model; - mat4 view; - mat4 proj; -} ubo; - -layout(location = 0) in vec3 inPosition; -layout(location = 1) in vec3 inColor; -layout(location = 2) in vec2 inTextureCoordinate; - -layout(location = 0) out vec3 fragColor; -layout(location = 1) out vec2 fragTextureCoordinate; - - -void main() { - gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); - /* gl_Position = vec4(inPosition, 1.0); */ - - /* debugPrintfEXT("inPosition %v3f, inColor %v3f", inPosition, inColor); */ - fragColor = inColor; - fragTextureCoordinate = inTextureCoordinate; -} diff --git a/src/shader/shader2D.frag b/src/shader/shader2D.frag deleted file mode 100644 index 5ac53ff..0000000 --- a/src/shader/shader2D.frag +++ /dev/null @@ -1,17 +0,0 @@ -#version 450 -#extension GL_EXT_debug_printf : enable - -layout(binding = 0) uniform sampler2D textureSampler; - -layout(location = 0) in vec3 fragColor; -layout(location = 1) in vec2 fragTextureCoordinate; - -layout(location = 0) out vec4 outColor; - -void main() { - /* outColor = vec4(fragColor, 1.0); */ - /* outColor = vec4(fragTextureCoordinate, 0.0, 1.0); */ - /* outColor = vec4(fragColor * texture(textureSampler, fragTextureCoordinate).rgb, 1.0); */ - outColor = texture(textureSampler, fragTextureCoordinate); - /* debugPrintfEXT("outColor %v3f", outColor); */ -} diff --git a/src/shader/shader2D.vert b/src/shader/shader2D.vert deleted file mode 100644 index d48fa9a..0000000 --- a/src/shader/shader2D.vert +++ /dev/null @@ -1,25 +0,0 @@ -#version 450 -#extension GL_EXT_debug_printf : enable - -/* 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 = 2) in vec2 inTextureCoordinate; - -layout(location = 0) out vec3 fragColor; -layout(location = 1) out vec2 fragTextureCoordinate; - - -void main() { - /* gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); */ - gl_Position = vec4(inPosition, 0.0, 1.0); - - /* debugPrintfEXT("inPosition %v2f, inColor %v3f", inPosition, inColor); */ - fragColor = inColor; - fragTextureCoordinate = inTextureCoordinate; -} diff --git a/src/shape.cpp b/src/shape.cpp index 88ddce4..e7e629c 100644 --- a/src/shape.cpp +++ b/src/shape.cpp @@ -2,7 +2,7 @@ #include "texture_manager.hpp" -namespace gz::vk { +namespace gz::vlk { Rectangle::Rectangle(float top, float left, uint32_t width, uint32_t height, glm::vec3 color, std::string&& texture) : top(top), left(left), width(width), height(height), color(color) { @@ -55,4 +55,4 @@ namespace gz::vk { } -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/shape.hpp b/src/shape.hpp index 4a0da76..ab8bbb3 100644 --- a/src/shape.hpp +++ b/src/shape.hpp @@ -3,7 +3,7 @@ #include "vertex.hpp" #include -namespace gz::vk { +namespace gz::vlk { // defined in texture_manager.hpp class TextureManager; class Shape { @@ -46,4 +46,4 @@ namespace gz::vk { glm::vec3 color; void generateVertices(); }; -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/utility/exceptions.cpp b/src/utility/exceptions.cpp index 828fb3d..7c88b40 100644 --- a/src/utility/exceptions.cpp +++ b/src/utility/exceptions.cpp @@ -1,9 +1,9 @@ #include "exceptions.hpp" -#include "vk_enum_string.h" +#include "vulkan_util.hpp" namespace gz { - VkException getVkException(VkResult result, std::string&& what, std::string&& functionName) { + VkException getVkException(vk::Result result, std::string&& what, std::string&& functionName) { std::string whatStr; if (!functionName.empty()) { whatStr += "Error in function: " + functionName + ": "; @@ -15,7 +15,7 @@ namespace gz { whatStr += what + ": "; } whatStr += "VkResult="; - whatStr += STR_VK_RESULT(result); + whatStr += ::toString(result); return VkException(whatStr); } } diff --git a/src/utility/exceptions.hpp b/src/utility/exceptions.hpp index e467c67..b653469 100644 --- a/src/utility/exceptions.hpp +++ b/src/utility/exceptions.hpp @@ -2,7 +2,8 @@ #include -#include +#define VULKAN_HPP_NO_CONSTRUCTORS +#include #include #include @@ -31,7 +32,8 @@ namespace gz { /** * @brief Return a VkException with a formatted string + * @todo Return different Exceptions depending in result or make this a constructor of VkException */ - VkException getVkException(VkResult result, std::string&& what="", std::string&& functionName=""); + VkException getVkException(vk::Result result, std::string&& what="", std::string&& functionName=""); } diff --git a/src/utility/texture_atlas.cpp b/src/utility/texture_atlas.cpp index d1b7946..63ad7bb 100644 --- a/src/utility/texture_atlas.cpp +++ b/src/utility/texture_atlas.cpp @@ -12,10 +12,10 @@ #include #include #include -#include + #include -namespace gz::vk { +namespace gz::vlk { std::string TextureImageArea::toString() const { return "<(" + gz::toString(x) + "," + gz::toString(y) + "), (" + gz::toString(width) + "x" + gz::toString(height) + ")>"; } @@ -29,12 +29,13 @@ TextureAtlas::TextureAtlas(VulkanInstance& instance, uint16_t slotWidth, uint16_ slotCountX(slotCountX), slotCountY(slotCountY) { #ifdef LOG_LEVEL_0 - LogCreateInfo logCI{}; - logCI.logfile = "textureAtlas.log"; - logCI.storeLog = false; - logCI.prefix = "TextureAtlas (" + gz::toString(slotCountX) + "x" + gz::toString(slotCountY) + ")X(" + gz::toString(slotWidth) + "x" + gz::toString(slotHeight) + ")"; - logCI.prefixColor = Color::GREEN; - logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; + LogCreateInfo logCI{ + .logfile = "textureAtlas.log", + .storeLog = false, + .prefix = "TextureAtlas (" + gz::toString(slotCountX) + "x" + gz::toString(slotCountY) + ")X(" + gz::toString(slotWidth) + "x" + gz::toString(slotHeight) + ")", + .prefixColor = Color::GREEN, + .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR, + }; tLog = Log(std::move(logCI)); #endif @@ -59,23 +60,24 @@ void TextureAtlas::cleanup() { void TextureAtlas::createImageResources() { - vk.createImage(slotWidth * slotCountX, slotHeight * slotCountY, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_LINEAR, - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + vk.createImage(slotWidth * slotCountX, slotHeight * slotCountY, vk::Format::eR8G8B8A8Srgb, vk::ImageTiling::eLinear, + vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, + vk::MemoryPropertyFlagBits::eDeviceLocal, textureImage, textureImageMemory); - VkCommandBuffer cmdBuffer = vk.beginSingleTimeCommands(POOL_GRAPHICS); - vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cmdBuffer); - VkImageSubresourceRange subresourceRange{}; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.baseMipLevel = 0; - subresourceRange.levelCount = 1; - subresourceRange.baseArrayLayer = 0; - subresourceRange.layerCount = 1; - vkCmdClearColorImage(cmdBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &missingTextureColor, 1, &subresourceRange); - vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &cmdBuffer); + vk::CommandBuffer cmdBuffer = vk.beginSingleTimeCommands(POOL_GRAPHICS); + vk.transitionImageLayout(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, &cmdBuffer); + vk::ImageSubresourceRange subresourceRange { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + cmdBuffer.clearColorImage(textureImage, vk::ImageLayout::eTransferDstOptimal, &settings::missingTextureColor, 1, &subresourceRange); + vk.transitionImageLayout(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, &cmdBuffer); vk.endSingleTimeCommands(cmdBuffer, POOL_GRAPHICS); - vk.createImageView(VK_FORMAT_R8G8B8A8_SRGB, textureImage, textureImageView, VK_IMAGE_ASPECT_COLOR_BIT); + vk.createImageView(vk::Format::eR8G8B8A8Srgb, textureImage, textureImageView, vk::ImageAspectFlagBits::eColor); vk.createTextureSampler(textureSampler); } @@ -161,22 +163,26 @@ std::pair TextureAtlas::addTexture(uint8_t* pixels, uint16 void TextureAtlas::blitTextureOnImage(uint8_t* pixels, uint16_t slotX, uint16_t slotY, uint16_t textureWidth, uint16_t textureHeight) { constexpr size_t BYTES_PER_PIXEL = 4; - VkDeviceSize imageSize = textureWidth * textureHeight * BYTES_PER_PIXEL; - VkBuffer stagingBuffer; + vk::DeviceSize imageSize = textureWidth * textureHeight * BYTES_PER_PIXEL; + vk::Buffer stagingBuffer; MemoryInfo stagingBufferMemory; - vk.createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + vk.createBuffer(imageSize, vk::BufferUsageFlagBits::eTransferSrc, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory); void* data; - vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, imageSize, NO_FLAGS, &data); + vk::Result result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, imageSize, vk::MemoryMapFlags(), &data); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to map staging buffer", "TextureAtlas::blitTextureOnImage"); + } + memcpy(data, pixels, static_cast(imageSize)); - vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); + vk.getDevice().unmapMemory(stagingBufferMemory.memory); - vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + vk.transitionImageLayout(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eTransferDstOptimal); vk.copyBufferToImage(stagingBuffer, textureImage, static_cast(slotWidth * slotX), static_cast(slotHeight * slotY), // offset static_cast(textureWidth), static_cast(textureHeight)); // dimensions - vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + vk.transitionImageLayout(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal); vk.destroyBuffer(stagingBuffer, stagingBufferMemory); } diff --git a/src/utility/texture_atlas.hpp b/src/utility/texture_atlas.hpp index e9063c5..01f4d06 100644 --- a/src/utility/texture_atlas.hpp +++ b/src/utility/texture_atlas.hpp @@ -3,7 +3,8 @@ #include "vulkan_allocator.hpp" #include #include -#include +#define VULKAN_HPP_NO_CONSTRUCTORS +#include #include #include @@ -14,7 +15,7 @@ #include #endif -namespace gz::vk { +namespace gz::vlk { /** * @brief Describes an area in the textureImage that is not in use */ @@ -61,8 +62,8 @@ namespace gz::vk { * @throws Exception when there is no space in the atlas to add the texture */ std::pair addTexture(uint8_t* pixels, uint16_t textureWidth, uint16_t textureHeight); - const VkImageView& getTextureImageView() const { return textureImageView; } - const VkSampler& getTextureSampler() const { return textureSampler; } + const vk::ImageView& getTextureImageView() const { return textureImageView; } + const vk::Sampler& getTextureSampler() const { return textureSampler; } std::string toString() const; @@ -81,10 +82,10 @@ namespace gz::vk { * the textureImage is created with missingTextureColor and then transitioned to SHADER_READ_ONLY_OPTIMAL layout. */ void createImageResources(); - VkImage textureImage; + vk::Image textureImage; MemoryInfo textureImageMemory; - VkImageView textureImageView; - VkSampler textureSampler; + vk::ImageView textureImageView; + vk::Sampler textureSampler; std::set freeAreas; /** @@ -103,4 +104,4 @@ namespace gz::vk { Log tLog; #endif }; -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/utility/texture_manager.cpp b/src/utility/texture_manager.cpp index b3fe585..480e219 100644 --- a/src/utility/texture_manager.cpp +++ b/src/utility/texture_manager.cpp @@ -3,22 +3,22 @@ #include "vulkan_instance.hpp" #include -#include -namespace gz::vk { +namespace gz::vlk { TextureManager::TextureManager(VulkanInstance& instance) : vk(instance) { - LogCreateInfo logCI{}; - logCI.logfile = "textureManager.log"; - logCI.storeLog = false; - logCI.prefix = "Texture"; - logCI.prefixColor = Color::GREEN; - logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; + LogCreateInfo logCI{ + .logfile = "textureManager.log", + .storeLog = false, + .prefix = "Texture", + .prefixColor = Color::GREEN, + .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR, + }; tLog = Log(std::move(logCI)); vk.registerCleanupCallback(std::bind(&TextureManager::cleanup, this)); - atlases.insert({ 0, TextureAtlas(vk, 24, 24, 24, 24) }); + atlases.emplace_back(TextureAtlas(vk, 24, 24, 24, 24)); createDescriptorSetLayout(); createDescriptorPool(); createDescriptorSet(); @@ -30,12 +30,10 @@ namespace gz::vk { void TextureManager::cleanup() { tLog.log0("cleanup: cleaning up"); - /* vkFreeDescriptorSets(vk.getDevice(), descriptorPool, 1, &descriptorSet); */ - vkDestroyDescriptorSetLayout(vk.getDevice(), descriptorSetLayout, NO_ALLOC); - vkDestroyDescriptorPool(vk.getDevice(), descriptorPool, NO_ALLOC); - for (auto& [i, atlas] : atlases) { + vk.getDevice().destroyDescriptorSetLayout(descriptorSetLayout, NO_ALLOC); + vk.getDevice().destroyDescriptorPool(descriptorPool, NO_ALLOC); + for (auto& atlas : atlases) { atlas.cleanup(); - } } @@ -46,8 +44,6 @@ namespace gz::vk { } TextureInfo& texI = textureInfos[textureName]; tLog.log0("getTexCoords", texCoords, "textureInfo: topleft", texI.texCoordTopLeft, "botright", texI.texCoordBottomRight); - /* texCoords.x = texI.texCoordTopLeft.x + texCoords.x * (texI.texCoordBottomRight.x - texI.texCoordTopLeft.x); */ - /* texCoords.y = texI.texCoordTopLeft.y + texCoords.y * (texI.texCoordBottomRight.y - texI.texCoordTopLeft.y); */ texCoords = texI.texCoordTopLeft + texCoords * (texI.texCoordBottomRight - texI.texCoordTopLeft); } @@ -60,11 +56,12 @@ namespace gz::vk { } TextureInfo& texI = textureInfos[textureName]; texI.atlas = 0; + // TODO auto texCoords = atlases.at(0).addTexture(pixels, textureWidth, textureHeight); stbi_image_free(pixels); tLog.log0("TextureManager::loadTextureFromFile: TexCoords of new image:", texCoords.first, texCoords.second); - texI.texCoordTopLeft = std::move(texCoords.first); - texI.texCoordBottomRight = std::move(texCoords.second); + texI.texCoordTopLeft = std::move(texCoords.first), + texI.texCoordBottomRight = std::move(texCoords.second), tLog.log0("TextureManager::loadTextureFromFile: After loading:", atlases.at(0)); } @@ -74,20 +71,20 @@ namespace gz::vk { // void TextureManager::createDescriptorSetLayout() { // combined image sampler - VkDescriptorSetLayoutBinding samplerLayoutBinding{}; - samplerLayoutBinding.binding = 0; - samplerLayoutBinding.descriptorCount = 1; - samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - /* samplerLayoutBinding.pImmutableSamplers = nullptr; */ + std::vector samplerLayoutBindings(atlases.size(), { + .binding = 0, + .descriptorType = vk::DescriptorType::eCombinedImageSampler, + .descriptorCount = 1, + .stageFlags = vk::ShaderStageFlagBits::eFragment, + /* .pImmutableSamplers = nullptr, */ + } + ); - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; - descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCI.bindingCount = 1; - descriptorSetLayoutCI.pBindings = &samplerLayoutBinding; + vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCI; + descriptorSetLayoutCI.setBindings(samplerLayoutBindings); - VkResult result = vkCreateDescriptorSetLayout(vk.getDevice(), &descriptorSetLayoutCI, nullptr, &descriptorSetLayout); - if (result != VK_SUCCESS) { + vk::Result result = vk.getDevice().createDescriptorSetLayout(&descriptorSetLayoutCI, nullptr, &descriptorSetLayout); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Could not create descriptorSetLayout", "TextureManager::createDescriptorSetLayout"); } /* vLog("createDescriptorSetLayout: Created descriptor set layout."); */ @@ -95,64 +92,56 @@ void TextureManager::createDescriptorSetLayout() { void TextureManager::createDescriptorPool() { - std::array poolSizes; - /* poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; */ - /* poolSizes[0].descriptorCount = static_cast(vk.getMaxFramesInFlight()); */ - poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - poolSizes[0].descriptorCount = static_cast(vk.getMaxFramesInFlight()); + std::vector poolSizes { + vk::DescriptorPoolSize { + .type = vk::DescriptorType::eCombinedImageSampler, + .descriptorCount = static_cast(vk.getMaxFramesInFlight()) + } + }; - VkDescriptorPoolCreateInfo poolCI{}; - poolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolCI.poolSizeCount = static_cast(poolSizes.size()); - poolCI.pPoolSizes = poolSizes.data(); - poolCI.maxSets = 1; - VkResult result = vkCreateDescriptorPool(vk.getDevice(), &poolCI, nullptr, &descriptorPool); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create descriptor pool", "TextureManager::createDescriptorPool"); - } + vk::DescriptorPoolCreateInfo poolCI { .maxSets = 1 }; + poolCI.setPoolSizes(poolSizes); + + vk::Result result; + std::tie(result, descriptorPool) = vk.getDevice().createDescriptorPool(poolCI); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create descriptor pool", "TextureManager::createDescriptorPool"); + } /* vLog("createDescriptorPool: Created descriptor pool."); */ } void TextureManager::createDescriptorSet() { - /* std::vector layouts(vk.getMaxFramesInFlight(), descriptorSetLayout); */ - VkDescriptorSetAllocateInfo setAI{}; - setAI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - setAI.descriptorPool = descriptorPool; - /* setAI.descriptorSetCount = static_cast(vk.getMaxFramesInFlight()); */ - /* setAI.pSetLayouts = layouts.data(); */ - setAI.descriptorSetCount = 1; - setAI.pSetLayouts = &descriptorSetLayout; + vk::DescriptorSetAllocateInfo setAI { + .descriptorPool = descriptorPool, + }; + setAI.setSetLayouts(descriptorSetLayout); - /* descriptorSets.resize(vk.getMaxFramesInFlight()); */ - /* VkResult result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, descriptorSets.data()); */ - VkResult result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, &descriptorSet); - if (result != VK_SUCCESS) { + auto [result, descriptorSetV] = vk.getDevice().allocateDescriptorSets(setAI); + descriptorSet = descriptorSetV.front(); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to create descriptor set", "TextureManager::createDescriptorPool"); } // configure sets - std::vector imageInfos; + std::vector imageInfos; for (auto it = atlases.cbegin(); it != atlases.cend(); it++) { imageInfos.emplace_back(); - imageInfos.back().imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfos.back().imageView = it->second.getTextureImageView(); - imageInfos.back().sampler = it->second.getTextureSampler(); + imageInfos.back().imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal; + imageInfos.back().imageView = it->getTextureImageView(); + imageInfos.back().sampler = it->getTextureSampler(); } - std::array descriptorW{}; - descriptorW[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorW[0].dstSet = descriptorSet; - descriptorW[0].dstBinding = 0; - descriptorW[0].dstArrayElement = 0; - descriptorW[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorW[0].descriptorCount = static_cast(imageInfos.size()); - descriptorW[0].pImageInfo = imageInfos.data(); + vk::WriteDescriptorSet descriptorW { + .dstSet = descriptorSet, + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorType = vk::DescriptorType::eCombinedImageSampler, + }; + descriptorW.setImageInfo(imageInfos); - uint32_t descriptorWriteCount = static_cast(descriptorW.size()); - uint32_t descriptorCopyCount = 0; - vkUpdateDescriptorSets(vk.getDevice(), descriptorWriteCount, descriptorW.data(), descriptorCopyCount, nullptr); - /* } */ - /* vLog("createDescriptorSets: Created descriptor sets."); */ + // 1 write, no copies + vk.getDevice().updateDescriptorSets(descriptorW, nullptr); + tLog.log0("createDescriptorSets: Created descriptor sets."); } -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/utility/texture_manager.hpp b/src/utility/texture_manager.hpp index 417f371..389ccff 100644 --- a/src/utility/texture_manager.hpp +++ b/src/utility/texture_manager.hpp @@ -10,7 +10,7 @@ #include -namespace gz::vk { +namespace gz::vlk { struct TextureInfo { uint32_t atlas; glm::vec2 texCoordTopLeft; @@ -28,30 +28,35 @@ namespace gz::vk { */ TextureManager(VulkanInstance& instance); void getTexCoords(const std::string& textureName, glm::vec2& texCoords); - const VkDescriptorSet& getDescriptorSet() const { return descriptorSet; } - const VkDescriptorSetLayout& getDescriptorSetLayout() const { return descriptorSetLayout; } + const vk::DescriptorSet& getDescriptorSet() const { return descriptorSet; } + const vk::DescriptorSetLayout& getDescriptorSetLayout() const { return descriptorSetLayout; } // TODO /// @todo take texture as argument - const TextureAtlas& getTextureAtlas() const { return atlases.at(0); }; + const TextureAtlas& getTextureAtlas() const { return atlases.at(0); } + uint32_t getAtlasCount() const { return static_cast(atlases.size()); } private: void cleanup(); void loadTextureFromFile(const std::string& textureName); - std::unordered_map atlases; + // TODO index currently has no meaning + std::vector atlases; + /** + * @brief Contains textureName : TextureInfo pairs + */ util::unordered_string_map textureInfos; VulkanInstance& vk; Log tLog; /** * @name Create desciptors * @details These functions create a desciptor with bindings for - * -# Combined Image Sampler (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) at binding 0 + * -# Array of combined image samplers (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) at binding 0. Array length is atlas count * @{ */ - VkDescriptorSetLayout descriptorSetLayout; - VkDescriptorPool descriptorPool; - VkDescriptorSet descriptorSet; - /* std::vector descriptorSets; */ + vk::DescriptorSetLayout descriptorSetLayout; + vk::DescriptorPool descriptorPool; + vk::DescriptorSet descriptorSet; + /* std::vector descriptorSets; */ /** * @brief Create a descriptor set layout * @details @@ -69,4 +74,4 @@ namespace gz::vk { }; -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/utility/vulkan_util.cpp b/src/utility/vulkan_util.cpp index 11922f3..8be2a38 100644 --- a/src/utility/vulkan_util.cpp +++ b/src/utility/vulkan_util.cpp @@ -1,9 +1,13 @@ #include "vulkan_util.hpp" #include #include +#include +#include +#define VULKAN_HPP_NO_CONSTRUCTORS +#include -namespace gz::vk { +namespace gz::vlk { // // CONVENIENCE // @@ -16,6 +20,9 @@ namespace gz::vk { f11.pNext = &f12; f12.pNext = &f13; } + + /* static_assert(sizeof(VkStructureType) != sizeof(vk::StructureType), "Objects do not have same size"); */ + /* static_assert(sizeof(VkPhysicalDeviceFeatures) != sizeof(vk::PhysicalDeviceFeatures), "Objects do not have same size"); */ bool PhysicalDeviceFeatures::requiredFeaturesAvailable(const PhysicalDeviceFeatures& requiredFeatures) const { // iterate over all the features in the structs // VkPhysicalDeviceFeatures2 @@ -68,53 +75,47 @@ namespace gz::vk { return true; } - void PipelineContainer::erase(const PipelineT& key, const VkDevice& device, const VkAllocationCallbacks* pAllocator) { - vkDestroyPipeline(device, pipelines[key].pipeline, pAllocator); - vkDestroyPipelineLayout(device, pipelines[key].layout, pAllocator); + void PipelineContainer::erase(const PipelineT& key, const vk::Device& device, const vk::AllocationCallbacks* pAllocator) { + device.destroyPipeline(pipelines[key].pipeline, pAllocator); + device.destroyPipelineLayout(pipelines[key].layout, pAllocator); pipelines.erase(pipelines.find(key)); } - PipelineContainer::iterator PipelineContainer::erase(const PipelineContainer::iterator& it, const VkDevice& device, const VkAllocationCallbacks* pAllocator) { - vkDestroyPipeline(device, it->second.pipeline, pAllocator); - vkDestroyPipelineLayout(device, it->second.layout, pAllocator); + PipelineContainer::iterator PipelineContainer::erase(const PipelineContainer::iterator& it, const vk::Device& device, const vk::AllocationCallbacks* pAllocator) { + device.destroyPipeline(it->second.pipeline, pAllocator); + device.destroyPipelineLayout(it->second.layout, pAllocator); return pipelines.erase(it); } - void PipelineContainer::destroy(const VkDevice& device, const VkAllocationCallbacks* pAllocator) { + void PipelineContainer::destroy(const vk::Device& device, const vk::AllocationCallbacks* pAllocator) { auto it = pipelines.begin(); while (it != pipelines.end()) { it = erase(it, device); } } - VkDependencyInfo getDepInfo(const VkImageMemoryBarrier2& barrier) { - VkDependencyInfo depI{}; - depI.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; - depI.imageMemoryBarrierCount = 1; - depI.pImageMemoryBarriers = &barrier; + vk::DependencyInfo getDepInfo(const vk::ImageMemoryBarrier2& barrier) { + vk::DependencyInfo depI { + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &barrier, + }; return depI; } - void getBufferMemoryRequirements(const VkDevice& device, const VkBuffer& buffer, VkBufferMemoryRequirementsInfo2& bufMemReq, VkMemoryRequirements2& memReq) { - bufMemReq.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2; - bufMemReq.pNext = nullptr; - bufMemReq.buffer = buffer; + /* void getBufferMemoryRequirements(const vk::Device& device, const vk::Buffer& buffer, vk::BufferMemoryRequirementsInfo2& bufMemReq, vk::MemoryRequirements2& memReq) { */ + /* bufMemReq.pNext = nullptr; */ + /* bufMemReq.buffer = buffer; */ - memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; - memReq.pNext = nullptr; - vkGetBufferMemoryRequirements2(device, &bufMemReq, &memReq); - } + /* memReq.pNext = nullptr; */ + /* vk::getBufferMemoryRequirements2(device, &bufMemReq, &memReq); */ + /* } */ - void getImageMemoryRequirements(const VkDevice& device, const VkImage& image, VkImageMemoryRequirementsInfo2& imMemReq, VkMemoryRequirements2& memReq) { - imMemReq.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2; - imMemReq.pNext = nullptr; - imMemReq.image = image; + /* void getImageMemoryRequirements(const vk::Device& device, const vk::Image& image, vk::ImageMemoryRequirementsInfo2& imMemReq, vk::MemoryRequirements2& memReq) { */ + /* imMemReq.image = image; */ - memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; - memReq.pNext = nullptr; - vkGetImageMemoryRequirements2(device, &imMemReq, &memReq); - } + /* memReq = device.getImageMemoryRequirements2(imMemReq); */ + /* } */ // @@ -142,7 +143,7 @@ namespace gz::vk { } -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/utility/vulkan_util.hpp b/src/utility/vulkan_util.hpp index 0e53fa7..2d6448b 100644 --- a/src/utility/vulkan_util.hpp +++ b/src/utility/vulkan_util.hpp @@ -5,9 +5,25 @@ #include #include #include -#include +#define VULKAN_HPP_NO_CONSTRUCTORS +#define VULKAN_HPP_NO_EXCEPTIONS +#include -namespace gz::vk { +#ifdef GZ_UTIL_STRING_CONCEPTS + static_assert(false, "gz-util/util/string_conversion.hpp is included before vulkan_util.hpp!"); +#endif + +template +concept VkToString = requires(const T& t) { + { vk::to_string(t) }; +}; + +template +inline std::string toString(const T& t) { + return vk::to_string(t); +} + +namespace gz::vlk { /** * @name Convenience structs * @details @@ -18,13 +34,14 @@ namespace gz::vk { * @brief Struct containing all physical device features structs * @details * Make sure to call vkGetPhysicalDeviceFeatures2 with the f member, not this struct itself + * @todo Redo with vulkan.hpp and vk::StructureChain */ struct PhysicalDeviceFeatures { /** * @brief Initialize the structs with sType and pNext chain f -> f11 -> f12 -> f13 */ PhysicalDeviceFeatures(); - VkPhysicalDeviceFeatures2 f{}; + VkPhysicalDeviceFeatures2 f {}; VkPhysicalDeviceVulkan11Features f11{}; VkPhysicalDeviceVulkan12Features f12{}; VkPhysicalDeviceVulkan13Features f13{}; @@ -38,8 +55,8 @@ namespace gz::vk { PL_3D, PL_2D }; struct Pipeline { - VkPipeline pipeline; - VkPipelineLayout layout; + vk::Pipeline pipeline; + vk::PipelineLayout layout; void operator=(const Pipeline& other) = delete; }; @@ -53,15 +70,15 @@ namespace gz::vk { /** * @brief Destroy the pipeline+layout and then remove the handles from the underlying map */ - void erase(const PipelineT& key, const VkDevice& device, const VkAllocationCallbacks* pAllocator=nullptr); + void erase(const PipelineT& key, const vk::Device& device, const vk::AllocationCallbacks* pAllocator=nullptr); /** * @brief Destroy the pipeline+layout and then remove the handles from the underlying map */ - iterator erase(const iterator& it, const VkDevice& device, const VkAllocationCallbacks* pAllocator=nullptr); + iterator erase(const iterator& it, const vk::Device& device, const vk::AllocationCallbacks* pAllocator=nullptr); /** * @brief Destroy all pipelines#layouts and then remove the handles from the underlying map */ - void destroy(const VkDevice& device, const VkAllocationCallbacks* pAllocator=nullptr); + void destroy(const vk::Device& device, const vk::AllocationCallbacks* pAllocator=nullptr); iterator begin() { return pipelines.begin(); } iterator end() { return pipelines.end(); } size_t size() const { return pipelines.size(); } @@ -71,9 +88,9 @@ namespace gz::vk { }; struct SwapChainSupport { - VkSurfaceCapabilitiesKHR capabilities; - std::vector formats; - std::vector presentModes; + vk::SurfaceCapabilities2KHR capabilities; + std::vector formats; + std::vector presentModes; }; @@ -84,12 +101,12 @@ namespace gz::vk { struct VerticesAndIndices { std::vector vertices; std::vector indices; - constexpr VkIndexType getIndexType() const { + constexpr vk::IndexType getIndexType() const { if (std::same_as) { - return VK_INDEX_TYPE_UINT16; + return vk::IndexType::eUint16; } else if (std::same_as) { - return VK_INDEX_TYPE_UINT32; + return vk::IndexType::eUint32; } } }; @@ -124,30 +141,30 @@ namespace gz::vk { /** - * @brief Get a VkDependencyInfo struct for a single image memory barrier + * @brief Get a vk::DependencyInfo struct for a single image memory barrier */ - VkDependencyInfo getDepInfo(const VkImageMemoryBarrier2& barrier); + vk::DependencyInfo getDepInfo(const vk::ImageMemoryBarrier2& barrier); /** * @brief Fill bufMeqReq and memReq * @details * Fill the structs and call vkGetBufferMemoryRequirements2() */ - void getBufferMemoryRequirements(const VkDevice& device, const VkBuffer& buffer, VkBufferMemoryRequirementsInfo2& bufMemReq, VkMemoryRequirements2& memReq); + /* void getBufferMemoryRequirements(const vk::Device& device, const vk::Buffer& buffer, vk::BufferMemoryRequirementsInfo2& bufMemReq, vk::MemoryRequirements2& memReq); */ /** * @brief Fill imMemReq and memReq * @details * Fill the structs and call vkGetImageMemoryRequirements2() */ - void getImageMemoryRequirements(const VkDevice& device, const VkImage& image, VkImageMemoryRequirementsInfo2& imMemReq, VkMemoryRequirements2& memReq); + /* void getImageMemoryRequirements(const vk::Device& device, const vk::Image& image, vk::ImageMemoryRequirementsInfo2& imMemReq, vk::MemoryRequirements2& memReq); */ /// @} /** * @brief Used for debugging * @see VulkanInstance::debugLog * @details - * Handles like VkDevice are pointers to the actual handle. + * Handles like vk::Device are pointers to the actual handle. * Register the handle to a vulkan object with this struct and call updateHandles(). * The handles set will then contain the actual address of the handle, as printed by the validation layers. * That means you can check a handle returned by a validation layer @@ -169,4 +186,33 @@ namespace gz::vk { }; -} // namespace gz::vk + + /** + * @brief Check if all required extensions are available + */ + template + bool areExtensionsAvailable(const RE& requiredExtensions, const AE& availableExtensions) + requires std::same_as, const char*&> and std::same_as, vk::ExtensionProperties&> + { + bool extensionAvailable; + for (const auto& requiredExtension : requiredExtensions) { + extensionAvailable = false; + for (const auto& extension : availableExtensions) { + if (strcmp(requiredExtension, extension.extensionName) == 0) { + extensionAvailable = true; + break; + } + } + if (!extensionAvailable) { + return false; + } + } + return true; + } + + /** + * @file + * @brief Various utility structs and functions, as well as toString() overload for vk objects + */ + +} // namespace gz::vlk diff --git a/src/vertex.cpp b/src/vertex.cpp index a6b7f31..1882631 100644 --- a/src/vertex.cpp +++ b/src/vertex.cpp @@ -1,20 +1,21 @@ #include "vertex.hpp" -#include +#define VULKAN_HPP_NO_CONSTRUCTORS +#include #include #include -namespace gz::vk { +namespace gz::vlk { const uint32_t BINDING = 0; template -VkFormat getVkFormat() { +vk::Format getVkFormat() { if (std::same_as) { - return VK_FORMAT_R32G32B32_SFLOAT; + return vk::Format::eR32G32B32Sfloat; } else if (std::same_as) { - return VK_FORMAT_R32G32_SFLOAT; + return vk::Format::eR32G32Sfloat; } } @@ -29,28 +30,29 @@ VkFormat getVkFormat() { template - VkVertexInputBindingDescription Vertex::getBindingDescription() { - VkVertexInputBindingDescription bindingD{}; - bindingD.binding = BINDING; - bindingD.stride = sizeof(Vertex); - bindingD.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + vk::VertexInputBindingDescription Vertex::getBindingDescription() { + vk::VertexInputBindingDescription bindingD { + .binding = BINDING, + .stride = sizeof(Vertex), + .inputRate = vk::VertexInputRate::eVertex, + }; return bindingD; } template - std::array Vertex::getAttributeDescriptions() { - std::array inputAttributeD{}; + std::array Vertex::getAttributeDescriptions() { + std::array inputAttributeD{}; inputAttributeD[0].binding = BINDING; inputAttributeD[0].location = 0; inputAttributeD[0].format = getVkFormat(); inputAttributeD[0].offset = offsetof(Vertex, pos); inputAttributeD[1].binding = BINDING; inputAttributeD[1].location = 1; - inputAttributeD[1].format = VK_FORMAT_R32G32B32_SFLOAT; + inputAttributeD[1].format = vk::Format::eR32G32B32Sfloat; inputAttributeD[1].offset = offsetof(Vertex, color); inputAttributeD[2].binding = BINDING; inputAttributeD[2].location = 2; - inputAttributeD[2].format = VK_FORMAT_R32G32_SFLOAT; + inputAttributeD[2].format = vk::Format::eR32G32Sfloat; inputAttributeD[2].offset = offsetof(Vertex, texCoord); return inputAttributeD; @@ -63,11 +65,11 @@ VkFormat getVkFormat() { template std::string Vertex::toString() const; template std::string Vertex::toString() const; - template VkVertexInputBindingDescription Vertex::getBindingDescription(); - template VkVertexInputBindingDescription Vertex::getBindingDescription(); - template std::array Vertex::getAttributeDescriptions(); - template std::array Vertex::getAttributeDescriptions(); + template vk::VertexInputBindingDescription Vertex::getBindingDescription(); + template vk::VertexInputBindingDescription Vertex::getBindingDescription(); + template std::array Vertex::getAttributeDescriptions(); + template std::array Vertex::getAttributeDescriptions(); template bool Vertex::operator==(const Vertex& other) const; template bool Vertex::operator==(const Vertex& other) const; -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/vertex.hpp b/src/vertex.hpp index d6b2b9f..b797ad6 100644 --- a/src/vertex.hpp +++ b/src/vertex.hpp @@ -6,17 +6,19 @@ #include #include -/* #include */ -struct VkVertexInputBindingDescription; -struct VkVertexInputAttributeDescription; +// defined in vulkan/vulkan.hpp +namespace vk { + struct VertexInputBindingDescription; + struct VertexInputAttributeDescription; +} -namespace gz::vk { +namespace gz::vlk { template concept VertexType = requires { - requires std::same_as; + requires std::same_as; requires std::ranges::forward_range; - requires std::same_as, VkVertexInputAttributeDescription>; + requires std::same_as, vk::VertexInputAttributeDescription>; }; template @@ -35,12 +37,12 @@ namespace gz::vk { glm::vec2 texCoord = { 0, 0 }; std::string toString() const; bool operator==(const Vertex& other) const; - static VkVertexInputBindingDescription getBindingDescription(); - static std::array getAttributeDescriptions(); + static vk::VertexInputBindingDescription getBindingDescription(); + static std::array getAttributeDescriptions(); }; // struct Vertex using Vertex3D = Vertex; using Vertex2D = Vertex; -} // namespace gz::vk +} // namespace gz::vlk @@ -48,9 +50,9 @@ namespace gz::vk { // HASHES // namespace std { - template - struct hash> { - size_t operator()(gz::vk::Vertex const& vertex) const { + template + struct hash> { + size_t operator()(gz::vlk::Vertex const& vertex) const { return ((hash()(vertex.pos)) ^ (hash()(vertex.color) << 1) >> 1 ) ^ (hash()(vertex.texCoord) << 1); diff --git a/src/vk_convert.cpp b/src/vk_convert.cpp index ba4e83c..e0e9f3a 100644 --- a/src/vk_convert.cpp +++ b/src/vk_convert.cpp @@ -1,6 +1,6 @@ #include "vk_convert.hpp" -bool vkBool2Bool(const VkBool32& b) { +bool vkBool2Bool(const vk::Bool32& b) { if (b == VK_TRUE) { return true; } @@ -9,7 +9,7 @@ bool vkBool2Bool(const VkBool32& b) { } }; -VkBool32 bool2VkBool(const bool& b) { +vk::Bool32 bool2VkBool(const bool& b) { if (b) { return VK_TRUE; } @@ -18,7 +18,7 @@ VkBool32 bool2VkBool(const bool& b) { } } -std::string vkBool2String(const VkBool32& b) { +std::string vkBool2String(const vk::Bool32& b) { if (b == VK_TRUE) { return "true"; } @@ -27,7 +27,7 @@ std::string vkBool2String(const VkBool32& b) { } }; -VkBool32 string2VkBool(const std::string& s) { +vk::Bool32 string2VkBool(const std::string& s) { if (s == "true") { return VK_TRUE; } diff --git a/src/vk_convert.hpp b/src/vk_convert.hpp index a7dd343..6d0be7d 100644 --- a/src/vk_convert.hpp +++ b/src/vk_convert.hpp @@ -1,9 +1,10 @@ -#include +#define VULKAN_HPP_NO_CONSTRUCTORS +#include #include -VkBool32 bool2VkBool(const bool& b); -bool vkBool2Bool(const VkBool32& b); +vk::Bool32 bool2VkBool(const bool& b); +bool vkBool2Bool(const vk::Bool32& b); -VkBool32 string2VkBool(const std::string& s); -std::string vkBool2String(const VkBool32& b); +vk::Bool32 string2VkBool(const std::string& s); +std::string vkBool2String(const vk::Bool32& b); diff --git a/src/vulkan_allocator.cpp b/src/vulkan_allocator.cpp index 68f9fa6..165bd0d 100644 --- a/src/vulkan_allocator.cpp +++ b/src/vulkan_allocator.cpp @@ -5,15 +5,14 @@ #include #include -#include -namespace gz::vk { +namespace gz::vlk { std::string MemoryBlock::toString() const { return std::string(""); } - DeviceMemory::DeviceMemory(VkDeviceSize size_) { + DeviceMemory::DeviceMemory(vk::DeviceSize size_) { size = size_; memory = VK_NULL_HANDLE; blocks.emplace_back(MemoryBlock{size, 0, true}); @@ -23,17 +22,18 @@ namespace gz::vk { VulkanAllocator::VulkanAllocator(VulkanInstance& instance) : vk(instance) { - LogCreateInfo logCI{}; - logCI.logfile = "vulkan_allocator.log"; - logCI.storeLog = false; - logCI.prefix = "Allocator"; - logCI.prefixColor = Color::BLACK; - logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; + LogCreateInfo logCI { + .logfile = "vulkan_allocator.log", + .storeLog = false, + .prefix = "Allocator", + .prefixColor = Color::BLACK, + .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR, + }; aLog = Log(std::move(logCI)); } - void VulkanAllocator::allocate(const VkMemoryAllocateInfo& allocI, const VkMemoryRequirements2& memReq, MemoryInfo& memoryInfo) { + void VulkanAllocator::allocate(const vk::MemoryAllocateInfo& allocI, const vk::MemoryRequirements2& memReq, MemoryInfo& memoryInfo) { aLog.log0("allocate: Requesting memory with ( size", toHexString(allocI.allocationSize), "), ( memoryTypeIndex", allocI.memoryTypeIndex, "), ( alignment", toHexString(memReq.memoryRequirements.alignment), ")"); @@ -72,7 +72,7 @@ namespace gz::vk { memoryInfo.offset = block->offset; memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex; - aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks); + /* aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks); */ return; } } @@ -80,13 +80,12 @@ namespace gz::vk { // if nothing is found, allocate new memory memory[allocI.memoryTypeIndex].emplace_back(DeviceMemory(allocI.allocationSize * TODO_ALLOCATION_SIZE_MULTIPLIIER)); - VkMemoryAllocateInfo allocI_{}; - allocI_.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + vk::MemoryAllocateInfo allocI_{}; allocI_.memoryTypeIndex = allocI.memoryTypeIndex; allocI_.allocationSize = memory[allocI.memoryTypeIndex].back().size; aLog.log0("allocate: Allocating new memory of size:", gz::toHexString(allocI_.allocationSize, 0), "(memory", memoryInfo.memoryTypeIndex, "-", gz::toString(memory[memoryInfo.memoryTypeIndex].size()) + ")"); - VkResult result = vkAllocateMemory(vk.getDevice(), &allocI_, NO_ALLOC, &memory[allocI.memoryTypeIndex].back().memory); - if (result != VK_SUCCESS) { + vk::Result result = vk.getDevice().allocateMemory(&allocI_, NO_ALLOC, &memory[allocI.memoryTypeIndex].back().memory); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to allocate memory", "VulkanAllocator::allocate"); } @@ -96,11 +95,11 @@ namespace gz::vk { deviceMemory.blocks.front().size -= allocI.allocationSize; deviceMemory.blocks.emplace_front(MemoryBlock{ allocI.allocationSize, 0, false }); - // alignment always satisfied with vkAllocateMemory() and offset 0 + // alignment always satisfied with vk::allocateMemory() and offset 0 memoryInfo.memory = deviceMemory.memory; memoryInfo.offset = 0; memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex; - aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(memory[memoryInfo.memoryTypeIndex].size()) + ") Blocks:", deviceMemory.blocks); + /* aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(memory[memoryInfo.memoryTypeIndex].size()) + ") Blocks:", deviceMemory.blocks); */ } @@ -136,11 +135,11 @@ namespace gz::vk { memoryInfo.memory = VK_NULL_HANDLE; memoryInfo.offset = 0; - aLog.log0("free: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks); + /* aLog.log0("free: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks); */ // if now there is only one free block, everything is free -> deallocate memory if (deviceMemory->blocks.size() == 1) { aLog.log0("free: Deallocating (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") of size:", gz::toHexString(deviceMemory->size, 0)); - vkFreeMemory(vk.getDevice(), deviceMemory->memory, NO_ALLOC); + vk.getDevice().freeMemory(deviceMemory->memory, NO_ALLOC); memory[memoryInfo.memoryTypeIndex].erase(deviceMemory); } return; @@ -160,11 +159,11 @@ namespace gz::vk { aLog.warning("cleanup: (memory", memType->first, "-", gz::toString(deviceMemory - memType->second.begin()) + ") Block not freed: ", *block); } aLog.log0("free: Deallocating (memory", memType->first, "-", gz::toString(deviceMemory - memType->second.begin()) + ") of size:", gz::toHexString(deviceMemory->size, 0)); - vkFreeMemory(vk.getDevice(), deviceMemory->memory, NO_ALLOC); + vk.getDevice().freeMemory(deviceMemory->memory, NO_ALLOC); } } memory.clear(); } -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/vulkan_allocator.hpp b/src/vulkan_allocator.hpp index 72947b9..015fe51 100644 --- a/src/vulkan_allocator.hpp +++ b/src/vulkan_allocator.hpp @@ -4,27 +4,28 @@ #include #include + +#define VULKAN_HPP_NO_EXCEPTIONS +#define VULKAN_HPP_NO_CONSTRUCTORS #include -#include #include #include -/* #include */ -namespace gz::vk { +namespace gz::vlk { /** - * @brief Contains information about a subsection (block) of a VkDeviceMemory + * @brief Contains information about a subsection (block) of a vk::DeviceMemory */ struct MemoryInfo { /** * @brief Handle of the memory */ - VkDeviceMemory memory = VK_NULL_HANDLE; + vk::DeviceMemory memory = VK_NULL_HANDLE; /** * @brief Offset into memory */ - VkDeviceSize offset = 0; + vk::DeviceSize offset = 0; /** * @brief The memoryTypeIndex memory was allocated from. Needed for VulkanAllocator::free() */ @@ -42,20 +43,20 @@ namespace gz::vk { }; /** - * @brief Manage a single VkDeviceMemory chunk + * @brief Manage a single vk::DeviceMemory chunk */ struct DeviceMemory { DeviceMemory() = delete; - DeviceMemory(VkDeviceSize size_); + DeviceMemory(vk::DeviceSize size_); - VkDeviceSize size; - VkDeviceMemory memory; + vk::DeviceSize size; + vk::DeviceMemory memory; std::list blocks; }; // if no memory is available, allocate a chunk of multiplier * requested size - constexpr VkDeviceSize TODO_ALLOCATION_SIZE_MULTIPLIIER = 10; + constexpr vk::DeviceSize TODO_ALLOCATION_SIZE_MULTIPLIIER = 10; // defined in vulkan_instance.hpp @@ -64,7 +65,7 @@ namespace gz::vk { /** * @brief Allocator for device local memory * @details - * Allocates larger chunks of VkDeviceMemory from which blocks can be @ref allocate() "allocated". + * Allocates larger chunks of vk::DeviceMemory from which blocks can be @ref allocate() "allocated". * * This class is for device local memory only, not for host memory. * You can not use it for vulkan memory allocation callbacks (pAllocator). @@ -73,34 +74,34 @@ namespace gz::vk { * The usage is explained with the example of creating and destroying a single buffer. * @code * // Create buffer handle - * VkBuffer buffer; + * vk::Buffer buffer; * // Create empty memory info struct * MemoryInfo bufferMI; * - * VkBufferCreateInfo bufferCI{} + * vk::BufferCreateInfo bufferCI{} * ... - * vkCreateBuffer(...); + * vk::createBuffer(...); * * // get memory requirements - * VkMemoryRequirements2 memReq; - * VkBufferMemoryRequirementsInfo2 bufMemReq; + * vk::MemoryRequirements2 memReq; + * vk::BufferMemoryRequirementsInfo2 bufMemReq; * // from vulkan_util.hpp, same exists for imageMemoryRequirements * getBufferMemoryRequirements(device, buffer, bufMemReq, memReq); * * // set allocation info - * VkMemoryAllocateInfo memAI{}; + * vk::MemoryAllocateInfo memAI { * ... - * memAI.memoryTypeIndex = VulkanInstance::findMemoryType(memReq.memoryRequirements.memoryTypeBits, wantedProperties); + * .memoryTypeIndex = VulkanInstance::findMemoryType(memReq.memoryRequirements.memoryTypeBits, wantedProperties), * * // allocate memory for the buffer * VulkanAllocator::allocate(memAI, memReq, bufferMI); * * // bind the buffer to the memory - * vkBindBufferMemory(device, buffer, bufferMI.memory, bufferMI.offset); + * device.bindBufferMemory(buffer, bufferMI.memory, bufferMI.offset); * * ... * - * vkDestroyBuffer(device, buffer); + * device.destroyBuffer(buffer); * VulkanAllocator::free(bufferMemoryInfo); * @endcode * @@ -110,23 +111,23 @@ namespace gz::vk { public: VulkanAllocator(VulkanInstance& instance); /** - * @brief Get a block from a VkDeviceMemory + * @brief Get a block from a vk::DeviceMemory * @details - * Get a block of allocI.allocationSize of a VkDeviceMemory that was allocated with allocI.memoryTypeIndex. + * Get a block of allocI.allocationSize of a vk::DeviceMemory that was allocated with allocI.memoryTypeIndex. * * When this function returns, memoryInfo will contain the information about the available block. * You can then bind something of size allocI.allocationSize to memoryInfo.memory at offset memoryInfo.offset. - * @throws VkException when a call to vkAllocateMemory is needed and fails + * @throws vk::Exception when a call to vkAllocateMemory is needed and fails * @todo Determine the size of new allocations - * @todo alignment, maybe use VkMemoryRequirements instead of VkMemoryAllocateInfo? + * @todo alignment, maybe use vk::MemoryRequirements instead of vk::MemoryAllocateInfo? * @todo maybe increase the block size of the allocated block so that the following blocks is already 16-aligned? */ - void allocate(const VkMemoryAllocateInfo& allocI, const VkMemoryRequirements2& memReq, MemoryInfo& memoryInfo); + void allocate(const vk::MemoryAllocateInfo& allocI, const vk::MemoryRequirements2& memReq, MemoryInfo& memoryInfo); /** * @brief Free a block allocated with allocate() * * When this function returns, memoryInfo will be reset to default values - * @throws VkUserError if memoryInfo was not allocated from this allocator + * @throws vk::UserError if memoryInfo was not allocated from this allocator */ void free(MemoryInfo& memoryInfo); @@ -147,4 +148,4 @@ namespace gz::vk { VulkanInstance& vk; }; // class VulkanAllocator -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/vulkan_instance.cpp b/src/vulkan_instance.cpp index db8b3cd..c27f4da 100644 --- a/src/vulkan_instance.cpp +++ b/src/vulkan_instance.cpp @@ -1,20 +1,17 @@ #include "vulkan_instance.hpp" #include "exceptions.hpp" -#include "font.hpp" +/* #include "font.hpp" */ -#include "vk_enum_string.h" -#include "vulkan_allocator.hpp" #include "vulkan_util.hpp" -#include -#include -#include + #include #include #include -#include -#include #include +#include +#include + #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" @@ -22,14 +19,14 @@ #include "tiny_obj_loader.h" #include -#include #include #include #include #include -#include +#define VULKAN_HPP_NO_CONSTRUCTORS +#include -namespace gz::vk { +namespace gz::vlk { using std::uint32_t; @@ -38,150 +35,22 @@ using std::uint32_t; // const unsigned int WIDTH = 600; const unsigned int HEIGHT = 600; - - const std::vector extensions = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - /* VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME */ - }; - const std::vector instanceExtensions = { - }; - - // // DEBUG - // - const std::vector validationLayers = { - "VK_LAYER_KHRONOS_validation", - }; #ifdef NDEBUG - constexpr bool enableValidationLayers = false; + constexpr bool enableValidationLayers = false; #else - constexpr bool enableValidationLayers = true; + constexpr bool enableValidationLayers = true; #endif - constexpr VkDebugUtilsMessageSeverityFlagsEXT debugMessageSevereties = - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - - constexpr VkDebugUtilsMessageTypeFlagsEXT debugMessageTypes = - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - const std::vector validationFeaturesEnable { - VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT, - VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT, - VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT - }; - const VkValidationFeaturesEXT validationFeatures { - VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, // sType - nullptr, // pNext - static_cast(validationFeaturesEnable.size()), // enabled feature count - validationFeaturesEnable.data(), // enable features - 0, // disabled feature count - nullptr // disabled features + // TODO: why needed at two separate places? + constexpr vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCI { + .pNext = &settings::validationFeatures, + .messageSeverity = settings::debugMessageSevereties, + .messageType = settings::debugMessageTypes, + .pfnUserCallback = VulkanInstance::debugLog, + .pUserData = nullptr, }; - /* constexpr VkDebugUtilsMessageTypeFlagsEXT debugFlags = */ - /* VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT | */ - /* VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT; */ - - constexpr VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCI { - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, // sType - &validationFeatures, // pNext - /* nullptr, // pNext */ - NO_FLAGS, // flags - debugMessageSevereties, // messageSeverety - debugMessageTypes, // messageType - VulkanInstance::debugLog, // pfnUserCallback - nullptr, // pUserData - - }; - - -// -// UTILITY FUNCTIONS -// - // - // EXTENSIONS - // - bool checkRequiredExtensionsAvailable(const std::vector& requiredExtensions, const std::vector& availableExtensions) { - bool extensionAvailable; - for (const auto& requiredExtension : requiredExtensions) { - extensionAvailable = false; - for (const auto& extension : availableExtensions) { - if (strcmp(requiredExtension, extension.extensionName) == 0) { - extensionAvailable = true; - break; - } - } - if (!extensionAvailable) { - return false; - } - } - return true; - } - - - std::vector getRequiredExtensions() { - uint32_t glfwExtensionCount = 0; - const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); - std::vector requiredExtensions(glfwExtensions, glfwExtensions + glfwExtensionCount); - - if (enableValidationLayers) { - requiredExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } - return requiredExtensions; - } - - - // check if all extensions are supported by device - bool deviceExtensionsSupported(VkPhysicalDevice device) { - uint32_t extensionCount; - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); - std::vector availableExtensions(extensionCount); - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); - - bool extensionAvailable; - for (const char* requiredExtension : extensions) { - extensionAvailable = false; - for (const auto& extensionProperties : availableExtensions) { - if (strcmp(requiredExtension, extensionProperties.extensionName) == 0) { - extensionAvailable = true; - break; - } - } - if (!extensionAvailable) { return false; } - } - return true; - } - - // - // VALIDATION LAYERS - // - // check if validation layers are supported/installed - bool validationLayersSupported() { - uint32_t layerCount; - vkEnumerateInstanceLayerProperties(&layerCount, nullptr); - std::vector availableLayers(layerCount); - vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); - - bool layerAvailable; - for (const char* requiredLayer : validationLayers) { - layerAvailable = false; - for (const auto& layerProperties : availableLayers) { - if (strcmp(requiredLayer, layerProperties.layerName) == 0) { - layerAvailable = true; - break; - } - } - if (!layerAvailable) { return false; } - } - return true; - } - - -// // // IMPLEMENTATION OF VULKANINSTANCE // @@ -220,7 +89,10 @@ using std::uint32_t; void VulkanInstance::cleanup() { - vkDeviceWaitIdle(device); + vk::Result result = device.waitIdle(); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to wait for device idle", "VulkanInstance::cleanup"); + } // call callbacks in reverse order for (auto it = cleanupCallbacks.rbegin(); it != cleanupCallbacks.rend(); it++) { (*it)(); @@ -230,86 +102,91 @@ using std::uint32_t; destroyCommandBuffers(commandBuffersBegin); destroyCommandBuffers(commandBuffersEnd); - /* vkDestroyImageView(device, textureImageView, nullptr); */ - /* vkDestroySampler(device, textureSampler, nullptr); */ - /* vkDestroyImage(device, textureImage, nullptr); */ - /* vkFreeMemory(device, textureImageMemory, nullptr); */ + /* device.destroyImageView(textureImageView, nullptr); */ + /* device.destroySampler(textureSampler, nullptr); */ + /* device.destroyImage(textureImage, nullptr); */ + /* device.freeMemory(textureImageMemory, nullptr); */ cleanupSwapChain(); for (size_t i = 0; i < getMaxFramesInFlight(); i++) { - vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr); - vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr); - vkDestroyFence(device, inFlightFences[i], nullptr); + device.destroySemaphore(imageAvailableSemaphores[i], nullptr); + device.destroySemaphore(renderFinishedSemaphores[i], nullptr); + device.destroyFence(inFlightFences[i], nullptr); } - /* vkFreeCommandBuffers(device, commandPoolGraphics, static_cast(commandBuffers2D.size()), commandBuffers2D.data()); */ - /* vkFreeCommandBuffers(device, commandPoolGraphics, static_cast(commandBuffers3D.size()), commandBuffers3D.data()); */ + /* device.freeCommandBuffers(commandPoolGraphics, static_cast(commandBuffers2D.size()), commandBuffers2D.data()); */ + /* device.freeCommandBuffers(commandPoolGraphics, static_cast(commandBuffers3D.size()), commandBuffers3D.data()); */ - vkDestroyCommandPool(device, commandPoolGraphics, nullptr); - vkDestroyCommandPool(device, commandPoolTransfer, nullptr); + device.destroyCommandPool(commandPoolGraphics, nullptr); + device.destroyCommandPool(commandPoolTransfer, nullptr); allocator.cleanup(); - vkDestroyDevice(device, nullptr); - vkDestroySurfaceKHR(instance, surface, nullptr); + device.destroy(); + instance.destroySurfaceKHR(surface); cleanupDebugMessenger(); - vkDestroyInstance(instance, nullptr); + instance.destroy(); glfwDestroyWindow(window); glfwTerminate(); } uint32_t VulkanInstance::beginFrameDraw() { - vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); + vk::Result result = device.waitForFences(inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to wait for fence", "VulkanInstance::beginFrameDraw"); + } uint32_t imageIndex; uint32_t blockFor = 0; /* uint64_t blockFor = UINT64_MAX; */ - VkResult result = vkAcquireNextImageKHR(device, swapChain, blockFor, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); - if (result == VK_ERROR_OUT_OF_DATE_KHR or frameBufferResized) { // result == VK_SUBOPTIMAL_KHR or - vLog.log0("drawFrame: result:", STR_VK_RESULT(result), "frameBufferResized:", frameBufferResized); + result = device.acquireNextImageKHR(swapChain, blockFor, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); + if (result == vk::Result::eErrorOutOfDateKHR or frameBufferResized) { // result == VK_SUBOPTIMAL_KHR or + vLog.log0("drawFrame: result:", result, "frameBufferResized:", frameBufferResized); frameBufferResized = false; recreateSwapChain(); return imageIndex; } - else if (result != VK_SUBOPTIMAL_KHR and result != VK_SUCCESS) { - /* vLog.error("Failed to acquire swap chain image. Result:", STR_VK_RESULT(result)); */ + else if (result != vk::Result::eSuboptimalKHR and result != vk::Result::eSuccess) { throw getVkException(result, "Failed to acquire swap chain image.", "beginFrameDraw"); } - vkResetFences(device, 1, &inFlightFences[currentFrame]); + result = device.resetFences(1, &inFlightFences[currentFrame]); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to reset fences", "VulkanInstance::beginFrameDraw"); + } // clear image - vkResetCommandBuffer(commandBuffersBegin[currentFrame], NO_FLAGS); - VkCommandBufferBeginInfo commandBufferBI{}; - commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - result = vkBeginCommandBuffer(commandBuffersBegin[currentFrame], &commandBufferBI); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to begin clear command buffer", "beginFrameDraw"); + commandBuffersBegin[currentFrame].reset(NO_CMD_RESET_FLAGS); + vk::CommandBufferBeginInfo commandBufferBI; + result = commandBuffersBegin[currentFrame].begin(commandBufferBI); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to begin clear command buffer", "VulkanInstance::beginFrameDraw"); } // transition to transfer dst layout - transitionImageLayout(scImages[imageIndex], scImageFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &commandBuffersBegin[currentFrame]); - VkImageMemoryBarrier2 imageBarrier{}; - imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; - imageBarrier.image = scImages[imageIndex]; - imageBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageBarrier.srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT; - /* imageBarrier.srcAccessMask = VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV; */ - imageBarrier.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; - imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageBarrier.subresourceRange.baseMipLevel = 0; - imageBarrier.subresourceRange.levelCount = 1; - imageBarrier.subresourceRange.baseArrayLayer = 0; - imageBarrier.subresourceRange.layerCount = 1; - VkDependencyInfo depI = getDepInfo(imageBarrier); - vkCmdPipelineBarrier2(commandBuffersBegin[currentFrame], &depI); + transitionImageLayout(scImages[imageIndex], scImageFormat, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, &commandBuffersBegin[currentFrame]); + vk::ImageMemoryBarrier2 imageBarrier { + .srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe, + .dstStageMask = vk::PipelineStageFlagBits2::eTransfer, + .oldLayout = vk::ImageLayout::eUndefined, + .newLayout = vk::ImageLayout::eTransferDstOptimal, + .image = scImages[imageIndex], + .subresourceRange { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + } + }; + vk::DependencyInfo depI = getDepInfo(imageBarrier); + commandBuffersBegin[currentFrame].pipelineBarrier2(depI); - result = vkEndCommandBuffer(commandBuffersBegin[currentFrame]); - if (result != VK_SUCCESS) { - vLog.error("Failed to record clear command buffer", "VkResult:", STR_VK_RESULT(result)); - throw getVkException(result, "Failed to record 2D - command buffer", "beginFrameDraw"); + result = commandBuffersBegin[currentFrame].end(); + if (result != vk::Result::eSuccess) { + vLog.error("Failed to record clear command buffer", "VkResult:", result); + throw getVkException(result, "Failed to record 2D - command buffer", "VulkanInstance::beginFrameDraw"); } commandBuffersToSubmitThisFrame.push_back(commandBuffersBegin[currentFrame]); @@ -318,57 +195,46 @@ using std::uint32_t; void VulkanInstance::endFrameDraw(uint32_t imageIndex) { - vkResetCommandBuffer(commandBuffersEnd[currentFrame], NO_FLAGS); - VkCommandBufferBeginInfo commandBufferBI{}; - commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - VkResult result = vkBeginCommandBuffer(commandBuffersEnd[currentFrame], &commandBufferBI); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to begin command buffer", "beginFrameDraw"); + commandBuffersEnd[currentFrame].reset(NO_CMD_RESET_FLAGS); + vk::CommandBufferBeginInfo commandBufferBI; + vk::Result result = commandBuffersEnd[currentFrame].begin(commandBufferBI); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to begin command buffer", "VulkanInstance::endFrameDraw"); } // transition to present layout - transitionImageLayout(scImages[imageIndex], scImageFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, &commandBuffersEnd[currentFrame]); - result = vkEndCommandBuffer(commandBuffersEnd[currentFrame]); - if (result != VK_SUCCESS) { - vLog.error("Failed to record clear command buffer", "VkResult:", STR_VK_RESULT(result)); - throw getVkException(result, "Failed to record command buffer", "beginFrameDraw"); + transitionImageLayout(scImages[imageIndex], scImageFormat, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::ePresentSrcKHR, &commandBuffersEnd[currentFrame]); + result = commandBuffersEnd[currentFrame].end(); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to record command buffer", "VulkanInstance::endFrameDraw"); } commandBuffersToSubmitThisFrame.push_back(commandBuffersEnd[currentFrame]); // submit all command buffers - VkSubmitInfo submitI{}; - submitI.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + vk::SubmitInfo submitI; + submitI.setWaitSemaphores(imageAvailableSemaphores[currentFrame]); + vk::PipelineStageFlags dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput; + submitI.setWaitDstStageMask(dstStageMask); + submitI.setSignalSemaphores(renderFinishedSemaphores[currentFrame]); + submitI.setCommandBuffers(commandBuffersToSubmitThisFrame); - VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]}; - VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; - submitI.waitSemaphoreCount = 1; - submitI.pWaitSemaphores = waitSemaphores; - submitI.pWaitDstStageMask = waitStages; - submitI.commandBufferCount = static_cast(commandBuffersToSubmitThisFrame.size()); - submitI.pCommandBuffers = commandBuffersToSubmitThisFrame.data(); - VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]}; - submitI.signalSemaphoreCount = 1; - submitI.pSignalSemaphores = signalSemaphores; - - uint32_t submitCount = 1; - result = vkQueueSubmit(graphicsQ, submitCount, &submitI, inFlightFences[currentFrame]); - if (result != VK_SUCCESS) { - vLog.error("Failed to submit draw command buffer", "VkResult:", STR_VK_RESULT(result)); - throw std::runtime_error("Failed to submit draw command buffer"); + result = graphicsQ.submit(submitI, inFlightFences[currentFrame]); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to submit command buffers", "VulkanInstance::endFrameDraw"); } commandBuffersToSubmitThisFrame.clear(); // present the image - VkPresentInfoKHR presentI{}; - presentI.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentI.waitSemaphoreCount = 1; - presentI.pWaitSemaphores = signalSemaphores; + vk::PresentInfoKHR presentI { + .pImageIndices = &imageIndex, + .pResults = nullptr, + }; + presentI.setWaitSemaphores(renderFinishedSemaphores[currentFrame]); + presentI.setSwapchains(swapChain); - VkSwapchainKHR swapChains[] = {swapChain}; - presentI.swapchainCount = 1; - presentI.pSwapchains = swapChains; - presentI.pImageIndices = &imageIndex; - presentI.pResults = nullptr; - vkQueuePresentKHR(presentQ, &presentI); + result = presentQ.presentKHR(presentI); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed present image", "VulkanInstance::endFrameDraw"); + } currentFrame = ++currentFrame % getMaxFramesInFlight(); } @@ -393,54 +259,60 @@ using std::uint32_t; // PUBLIC INTERFACE: VARIOUS UTILITY - void VulkanInstance::submitThisFrame(VkCommandBuffer& cmdBuffer) { + void VulkanInstance::submitThisFrame(vk::CommandBuffer& cmdBuffer) { commandBuffersToSubmitThisFrame.push_back(cmdBuffer); } - void VulkanInstance::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) { - VkCommandBuffer cmdBuffer = beginSingleTimeCommands(POOL_TRANSFER); - VkBufferCopy copyRegion{}; - copyRegion.srcOffset = 0; - copyRegion.dstOffset = 0; - copyRegion.size = size; - uint32_t copyRegionCount = 1; - vkCmdCopyBuffer(cmdBuffer, srcBuffer, dstBuffer, copyRegionCount, ©Region); + void VulkanInstance::copyBuffer(vk::Buffer srcBuffer, vk::Buffer dstBuffer, vk::DeviceSize size) { + vk::CommandBuffer cmdBuffer = beginSingleTimeCommands(POOL_TRANSFER); + vk::BufferCopy copyRegion { + .srcOffset = 0, + .dstOffset = 0, + .size = size, + }; + cmdBuffer.copyBuffer(srcBuffer, dstBuffer, copyRegion); endSingleTimeCommands(cmdBuffer, POOL_TRANSFER); } - VkCommandBuffer VulkanInstance::beginSingleTimeCommands(InstanceCommandPool commandPool) { - VkCommandBufferAllocateInfo allocI{}; - allocI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocI.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vk::CommandBuffer VulkanInstance::beginSingleTimeCommands(InstanceCommandPool commandPool) { + vk::CommandBufferAllocateInfo allocI { + .level = vk::CommandBufferLevel::ePrimary, + .commandBufferCount = 1, + }; if (commandPool == POOL_TRANSFER) { - allocI.commandPool = commandPoolTransfer; + allocI.setCommandPool(commandPoolTransfer); } else { - allocI.commandPool = commandPoolGraphics; + allocI.setCommandPool(commandPoolGraphics); } - allocI.commandBufferCount = 1; - VkCommandBuffer cmdBuffer; - vkAllocateCommandBuffers(device, &allocI, &cmdBuffer); + vk::CommandBuffer cmdBuffer; + vk::Result result = device.allocateCommandBuffers(&allocI, &cmdBuffer); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to allocate command buffer", "beginSingleTimeCommands"); + } - VkCommandBufferBeginInfo beginI{}; - beginI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuffer, &beginI); + vk::CommandBufferBeginInfo beginI { + .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit, + }; + result = cmdBuffer.begin(beginI); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to begin command buffer", "beginSingleTimeCommands"); + } return cmdBuffer; } - void VulkanInstance::endSingleTimeCommands(VkCommandBuffer cmdBuffer, InstanceCommandPool commandPool) { - VkResult result = vkEndCommandBuffer(cmdBuffer); - if (result != VK_SUCCESS) { + void VulkanInstance::endSingleTimeCommands(vk::CommandBuffer cmdBuffer, InstanceCommandPool commandPool) { + vk::Result result = cmdBuffer.end(); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to end commandBuffer", "endSingleTimeCommands"); } - VkCommandPool cmdPool; - VkQueue q; + vk::CommandPool cmdPool; + vk::Queue q; if (commandPool == POOL_TRANSFER) { cmdPool = commandPoolTransfer; q = transferQ; @@ -450,30 +322,28 @@ using std::uint32_t; q = graphicsQ; } - VkSubmitInfo submitI{}; - submitI.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitI.commandBufferCount = 1; - submitI.pCommandBuffers = &cmdBuffer; - uint32_t submitCount = 1; - result = vkQueueSubmit(q, submitCount, &submitI, VK_NULL_HANDLE); - if (result != VK_SUCCESS) { + vk::SubmitInfo submitI; + submitI.setCommandBuffers(cmdBuffer); + + result = q.submit(submitI); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to submit commandBuffer", "endSingleTimeCommands"); } - result = vkQueueWaitIdle(q); - if (result != VK_SUCCESS) { + + result = q.waitIdle(); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to wait for queue idle", "endSingleTimeCommands"); } - const uint32_t commandBufferCount = 1; - vkFreeCommandBuffers(device, cmdPool, commandBufferCount, &cmdBuffer); + device.freeCommandBuffers(cmdPool, cmdBuffer); } - void VulkanInstance::loadModel(VerticesAndIndices& model) { + void VulkanInstance::loadModel(const std::string& path, VerticesAndIndices& model) { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; std::string warnings, errors; - if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warnings, &errors, MODEL_PATH.c_str())) { + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warnings, &errors, path.c_str())) { vLog.warning("Warning from tinyobj::LoadObj: ", warnings); throw gz::Exception("Error loading obj: " + errors, "loadModel"); } @@ -505,46 +375,37 @@ using std::uint32_t; } } -// TODO - // DEPTH - /* VkFormat VulkanInstance::findDepthFormat() { */ - /* return findSupportedFormat({ VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); */ - /* } */ - // PUBLIC INTERFACE: CREATION AND DESTRUCTION // COMMAND BUFFER - void VulkanInstance::createCommandBuffers(std::vector& commandBuffers) { + void VulkanInstance::createCommandBuffers(std::vector& commandBuffers) { commandBuffers.resize(getMaxFramesInFlight()); - VkCommandBufferAllocateInfo commandBufferAI{}; - commandBufferAI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - commandBufferAI.commandPool = commandPoolGraphics; - commandBufferAI.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - commandBufferAI.commandBufferCount = static_cast(commandBuffers.size()); - VkResult result = vkAllocateCommandBuffers(device, &commandBufferAI, commandBuffers.data()); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create command buffer", "createCommandBuffer"); + vk::CommandBufferAllocateInfo commandBufferAI { + .commandPool = commandPoolGraphics, + .level = vk::CommandBufferLevel::ePrimary, + .commandBufferCount = static_cast(commandBuffers.size()), + }; + vk::Result result = device.allocateCommandBuffers(&commandBufferAI, commandBuffers.data()); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create allocate buffers", "VulkanInstance::createCommandBuffers"); } } - void VulkanInstance::destroyCommandBuffers(std::vector& commandBuffers) { - vkFreeCommandBuffers(device, commandPoolGraphics, static_cast(commandBuffers.size()), commandBuffers.data()); + void VulkanInstance::destroyCommandBuffers(std::vector& commandBuffers) { + device.freeCommandBuffers(commandPoolGraphics, commandBuffers); commandBuffers.resize(0); } // DESCRIPTORS SET LAYOUTS - void VulkanInstance::createDescriptorSetLayout(std::vector bindings, VkDescriptorSetLayout& layout) { - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; - descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCI.bindingCount = static_cast(bindings.size()); - descriptorSetLayoutCI.pBindings = bindings.data(); + void VulkanInstance::createDescriptorSetLayout(std::vector bindings, vk::DescriptorSetLayout& layout) { + vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCI; + descriptorSetLayoutCI.setBindings(bindings); - - VkResult result = vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &layout); - if (result != VK_SUCCESS) { - throw getVkException(result, "Could not create descriptorSetLayout", "createDescriptorSetLayout"); + vk::Result result = device.createDescriptorSetLayout(&descriptorSetLayoutCI, NO_ALLOC, &layout); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Could not create descriptorSetLayout", "VulkanInstance::createDescriptorSetLayout"); } /* vLog.log0("createDescriptorSetLayout: Created descriptor set layout."); */ } @@ -552,238 +413,224 @@ using std::uint32_t; // GRAPHICS PIPELINE template - void VulkanInstance::createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector& descriptorSetLayouts, bool useDepthStencil, VkRenderPass& renderPass, Pipeline& pipeline) { + void VulkanInstance::createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector& descriptorSetLayouts, bool useDepthStencil, vk::RenderPass& renderPass, Pipeline& pipeline, vk::SpecializationInfo* fragSI, vk::SpecializationInfo* vertSI) { auto vertShaderCode = readFile(vertexShader); auto fragShaderCode = readFile(fragmentShader); - VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); - VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); + vk::ShaderModule vertShaderModule = createShaderModule(vertShaderCode); + vk::ShaderModule fragShaderModule = createShaderModule(fragShaderCode); - VkPipelineShaderStageCreateInfo vertexShaderStageCI{}; - vertexShaderStageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vertexShaderStageCI.stage = VK_SHADER_STAGE_VERTEX_BIT; - vertexShaderStageCI.module = vertShaderModule; - vertexShaderStageCI.pName = "main"; - /* vssCreateInfo.pSpecializationInfo = nullptr; */ + vk::PipelineShaderStageCreateInfo vertexShaderStageCI { + .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertShaderModule, + .pName = "main", + .pSpecializationInfo = vertSI, + }; - VkPipelineShaderStageCreateInfo fragmentShaderStageCI{}; - fragmentShaderStageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - fragmentShaderStageCI.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - fragmentShaderStageCI.module = fragShaderModule; - fragmentShaderStageCI.pName = "main"; - /* vssCreateInfo.pSpecializationInfo = nullptr; */ + vk::PipelineShaderStageCreateInfo fragmentShaderStageCI { + .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragShaderModule, + .pName = "main", + .pSpecializationInfo = fragSI, + }; - VkPipelineShaderStageCreateInfo shaderStagesCI[] = { vertexShaderStageCI, fragmentShaderStageCI }; + vk::PipelineShaderStageCreateInfo shaderStagesCI[] = { vertexShaderStageCI, fragmentShaderStageCI }; - VkVertexInputBindingDescription bindingD = VertexT::getBindingDescription(); - // array + vk::VertexInputBindingDescription bindingD = VertexT::getBindingDescription(); + // array auto attributeD = VertexT::getAttributeDescriptions(); - VkPipelineVertexInputStateCreateInfo vertexInputStateCI{}; - vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputStateCI.vertexBindingDescriptionCount = 1; - vertexInputStateCI.pVertexBindingDescriptions = &bindingD; - vertexInputStateCI.vertexAttributeDescriptionCount = static_cast(attributeD.size());; - vertexInputStateCI.pVertexAttributeDescriptions = attributeD.data(); + vk::PipelineVertexInputStateCreateInfo vertexInputStateCI; + vertexInputStateCI.setVertexAttributeDescriptions(attributeD); + vertexInputStateCI.setVertexBindingDescriptions(bindingD); - VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{}; - inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - inputAssemblyStateCI.primitiveRestartEnable = VK_FALSE; + vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCI { + .topology = vk::PrimitiveTopology::eTriangleList, + .primitiveRestartEnable = VK_FALSE, + }; - VkViewport viewport{}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = static_cast(scExtent.width); - viewport.height = static_cast(scExtent.height); - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; + vk::Viewport viewport { + .x = 0.0f, + .y = 0.0f, + .width = static_cast(scExtent.width), + .height = static_cast(scExtent.height), + .minDepth = 0.0f, + .maxDepth = 1.0f, + }; - VkRect2D scissor{}; - scissor.offset = {0, 0}; - scissor.extent = scExtent; + vk::Rect2D scissor { + .offset = {0, 0}, + .extent = scExtent, + }; - VkPipelineViewportStateCreateInfo viewportStateCI{}; - viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportStateCI.viewportCount = 1; - viewportStateCI.pViewports = &viewport; - viewportStateCI.scissorCount = 1; - viewportStateCI.pScissors = &scissor; + vk::PipelineViewportStateCreateInfo viewportStateCI { + .viewportCount = 1, + .pViewports = &viewport, + .scissorCount = 1, + .pScissors = &scissor, + }; - VkPipelineRasterizationStateCreateInfo rasterizerCI{}; - rasterizerCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizerCI.depthClampEnable = VK_FALSE; - rasterizerCI.rasterizerDiscardEnable = VK_FALSE; - rasterizerCI.polygonMode = VK_POLYGON_MODE_FILL; - rasterizerCI.lineWidth = 1.0f; - rasterizerCI.cullMode = VK_CULL_MODE_BACK_BIT; - // not clockwise because of inverted y axis from glm - rasterizerCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizerCI.depthBiasEnable = VK_FALSE; - /* rasterizerCI.depthBiasConstantFactor = 0.0f; */ - /* rasterizerCI.depthBiasClamp = 0.0f; */ - /* rasterizerCI.depthBiasSlopeFactor = 0.0f; */ + vk::PipelineRasterizationStateCreateInfo rasterizerCI { + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = vk::PolygonMode::eFill, + .cullMode = vk::CullModeFlagBits::eBack, + // not clockwise because of inverted y axis from glm + .frontFace = vk::FrontFace::eCounterClockwise, + .depthBiasEnable = VK_FALSE, + .lineWidth = 1.0f, + /* .depthBiasConstantFactor = 0.0f, */ + /* .depthBiasClamp = 0.0f, */ + /* .depthBiasSlopeFactor = 0.0f, */ + }; - VkPipelineMultisampleStateCreateInfo multisampleStateCI{}; - multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampleStateCI.sampleShadingEnable = VK_FALSE; - multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - /* multisampleStateCI.minSampleShading = 1.0f; */ - /* multisampleStateCI.pSampleMask = nullptr; */ - /* multisampleStateCI.alphaToCoverageEnable = VK_FALSE; */ - /* multisampleStateCI.alphaToOneEnable = VK_FALSE; */ + vk::PipelineMultisampleStateCreateInfo multisampleStateCI { + .rasterizationSamples = vk::SampleCountFlagBits::e1, + .sampleShadingEnable = VK_FALSE, + /* .minSampleShading = 1.0f, */ + /* .pSampleMask = nullptr, */ + /* .alphaToCoverageEnable = VK_FALSE, */ + /* .alphaToOneEnable = VK_FALSE, */ + }; - VkPipelineColorBlendAttachmentState colorBlendAttachment{}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - colorBlendAttachment.blendEnable = VK_FALSE; - /* colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; */ - /* colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; */ - /* colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; */ - /* colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; */ - /* colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; */ - /* colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; */ + vk::PipelineColorBlendAttachmentState colorBlendAttachment { + .blendEnable = VK_FALSE, + /* .srcColorBlendFactor = vk::BlendFactor::eOne, */ + /* .dstColorBlendFactor = vk::BlendFactor::eZero, */ + /* .colorBlendOp = vk::BlendOp::eAdd, */ + /* .srcAlphaBlendFactor = vk::BlendFactor::eOne, */ + /* .dstAlphaBlendFactor = vk::BlendFactor::eZero, */ + /* .alphaBlendOp = vk::BlendOp::eAdd, */ + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + }; - VkPipelineColorBlendStateCreateInfo colorBlendCI{}; - colorBlendCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlendCI.logicOpEnable = VK_FALSE; - /* colorBlendCI.logicOp = VK_LOGIC_OP_COPY; */ - colorBlendCI.attachmentCount = 1; - colorBlendCI.pAttachments = &colorBlendAttachment; + vk::PipelineColorBlendStateCreateInfo colorBlendCI { + .logicOpEnable = VK_FALSE, + }; + colorBlendCI.setAttachments(colorBlendAttachment); colorBlendCI.blendConstants[0] = 0.0f; colorBlendCI.blendConstants[1] = 0.0f; colorBlendCI.blendConstants[2] = 0.0f; colorBlendCI.blendConstants[3] = 0.0f; - /* std::vector dynamicStates = { */ - /* VK_DYNAMIC_STATE_VIEWPORT, */ - /* VK_DYNAMIC_STATE_LINE_WIDTH */ + /* std::vector dynamicStates = { */ + /* vk::DynamicState::eViewport, */ + /* vk::DynamicState::eLineWidth */ /* }; */ - /* VkPipelineDynamicStateCreateInfo dynamicState{}; */ - /* dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; */ + /* vk::PipelineDynamicStateCreateInfo dynamicState { */ /* dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); */ /* dynamicState.pDynamicStates = dynamicStates.data(); */ - VkPipelineDepthStencilStateCreateInfo depthStencilCI{}; - depthStencilCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencilCI.depthTestEnable = VK_TRUE; - depthStencilCI.depthWriteEnable = VK_TRUE; - depthStencilCI.depthCompareOp = VK_COMPARE_OP_LESS; - depthStencilCI.depthBoundsTestEnable = VK_FALSE; - /* depthStencilCI.minDepthBounds = 0.0f; */ - /* depthStencilCI.maxDepthBounds = 1.0f; */ - depthStencilCI.stencilTestEnable = VK_FALSE; - /* depthStencilCI.front = {}; */ - /* depthStencilCI.back = {}; */ + vk::PipelineDepthStencilStateCreateInfo depthStencilCI { + .depthTestEnable = VK_TRUE, + .depthWriteEnable = VK_TRUE, + .depthCompareOp = vk::CompareOp::eLess, + .depthBoundsTestEnable = VK_FALSE, + /* .minDepthBounds = 0.0f, */ + /* .maxDepthBounds = 1.0f, */ + .stencilTestEnable = VK_FALSE, + /* .front = {}, */ + /* .back = {}, */ + }; - VkPipelineLayoutCreateInfo pipelineLayoutCI{}; - pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - /* pipelineLayoutCI.pushConstantRangeCount = 0; */ - /* pipelineLayoutCI.pPushConstantRanges = nullptr; */ - pipelineLayoutCI.setLayoutCount = static_cast(descriptorSetLayouts.size()); - pipelineLayoutCI.pSetLayouts = descriptorSetLayouts.data(); - VkResult result = vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipeline.layout); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create pipeline layout", "createGraphicsPipeline"); + vk::PipelineLayoutCreateInfo pipelineLayoutCI; + /* pipelineLayoutCI.setPushConstantRanges() */ + pipelineLayoutCI.setSetLayouts(descriptorSetLayouts); + vk::Result result = device.createPipelineLayout(&pipelineLayoutCI, nullptr, &pipeline.layout); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create pipeline layout", "VulkanInstance::createGraphicsPipeline"); } - VkGraphicsPipelineCreateInfo pipelineCI{}; - pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineCI.stageCount = 2; - pipelineCI.pStages = shaderStagesCI; - pipelineCI.pVertexInputState = &vertexInputStateCI; - pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; - pipelineCI.pViewportState = &viewportStateCI; - pipelineCI.pRasterizationState = &rasterizerCI; - pipelineCI.pMultisampleState = &multisampleStateCI; - if (useDepthStencil) { - pipelineCI.pDepthStencilState = &depthStencilCI; - } - else { - pipelineCI.pDepthStencilState = nullptr; - } - pipelineCI.pColorBlendState = &colorBlendCI; - /* pipelineCI.pDynamicState = nullptr; */ - pipelineCI.layout = pipeline.layout; - pipelineCI.renderPass = renderPass; - pipelineCI.subpass = 0; - /* pipelineCI.basePipelineHandle = VK_NULL_HANDLE; */ - /* pipelineCI.basePipelineIndex = -1; */ + vk::GraphicsPipelineCreateInfo pipelineCI { + .pVertexInputState = &vertexInputStateCI, + .pInputAssemblyState = &inputAssemblyStateCI, + .pViewportState = &viewportStateCI, + .pRasterizationState = &rasterizerCI, + .pMultisampleState = &multisampleStateCI, + .pDepthStencilState = useDepthStencil ? &depthStencilCI : nullptr, + .pColorBlendState = &colorBlendCI, + /* .pDynamicState = nullptr, */ + .layout = pipeline.layout, + .renderPass = renderPass, + .subpass = 0, + /* .basePipelineHandle = VK_NULL_HANDLE, */ + /* .basePipelineIndex = -1, */ + }; + pipelineCI.setStages(shaderStagesCI); - result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineCI, nullptr, &pipeline.pipeline); - if (result != VK_SUCCESS) { + // result, vector + auto [result2, pipelines] = device.createGraphicsPipelines(VK_NULL_HANDLE, pipelineCI, NO_ALLOC); + pipeline.pipeline = pipelines.front(); + if (result2 != vk::Result::eSuccess) { throw getVkException(result, "Could not create graphics pipeline", "createGraphicsPipeline"); } - vkDestroyShaderModule(device, vertShaderModule, nullptr); - vkDestroyShaderModule(device, fragShaderModule, nullptr); + device.destroyShaderModule(vertShaderModule, nullptr); + device.destroyShaderModule(fragShaderModule, nullptr); vLog.log0("createGraphicsPipeline: Created graphics pipeline."); } - template void VulkanInstance::createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector& descriptorSetLayouts, bool useDepthStencil, VkRenderPass& renderPass, Pipeline& pipeline); - template void VulkanInstance::createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector& descriptorSetLayouts, bool useDepthStencil, VkRenderPass& renderPass, Pipeline& pipeline); + template void VulkanInstance::createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector& descriptorSetLayouts, bool useDepthStencil, vk::RenderPass& renderPass, Pipeline& pipeline, vk::SpecializationInfo* fragSI, vk::SpecializationInfo* vertSI); + template void VulkanInstance::createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector& descriptorSetLayouts, bool useDepthStencil, vk::RenderPass& renderPass, Pipeline& pipeline, vk::SpecializationInfo* fragSI, vk::SpecializationInfo* vertSI); // SHADER MODULE - VkShaderModule VulkanInstance::createShaderModule(const std::vector& code) { - VkShaderModuleCreateInfo smCreateInfo{}; - smCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - smCreateInfo.codeSize = code.size(); - smCreateInfo.pCode = reinterpret_cast(code.data()); + vk::ShaderModule VulkanInstance::createShaderModule(const std::vector& code) { + vk::ShaderModuleCreateInfo shaderModuleCI { + .codeSize = code.size(), + .pCode = reinterpret_cast(code.data()), + }; - VkShaderModule shaderModule{}; - - VkResult result = vkCreateShaderModule(device, &smCreateInfo, nullptr, &shaderModule); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create shader module. Code size: " + std::to_string(code.size()), "createShaderModule"); + auto [result, shaderModule] = device.createShaderModule(shaderModuleCI, NO_ALLOC); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create shader module. Code size: " + std::to_string(code.size()), "VulkanInstance::createShaderModule"); } return shaderModule; } // BUFFER - void VulkanInstance::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, MemoryInfo& bufferMI, VkSharingMode sharingMode, std::vector* qFamiliesWithAccess) { - VkBufferCreateInfo bufferCI{}; - bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferCI.size = size; - bufferCI.usage = usage; - bufferCI.sharingMode = sharingMode; - std::vector queueFamiliesWithAccess; - if (sharingMode == VK_SHARING_MODE_CONCURRENT) { + void VulkanInstance::createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties, vk::Buffer& buffer, MemoryInfo& bufferMI, vk::SharingMode sharingMode, std::vector* qFamiliesWithAccess) { + vk::BufferCreateInfo bufferCI { + .size = size, + .usage = usage, + .sharingMode = sharingMode, + }; + /* std::vector queueFamiliesWithAccess; */ + if (sharingMode == vk::SharingMode::eConcurrent) { if (qFamiliesWithAccess == nullptr) { - throw VkUserError("Sharing mode is VK_SHARING_MODE_CONCURRENT but qFamiliesWithAccess is nullptr", "createBuffer"); + throw VkUserError("Sharing mode is vk::SharingMode::eConcurrent but qFamiliesWithAccess is nullptr", "VulkanInstance::createBuffer"); } - bufferCI.queueFamilyIndexCount = static_cast(qFamiliesWithAccess->size()); - bufferCI.pQueueFamilyIndices = qFamiliesWithAccess->data(); + bufferCI.setQueueFamilyIndices(*qFamiliesWithAccess); } - VkResult result = vkCreateBuffer(device, &bufferCI, nullptr, &buffer); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create buffer", "createBuffer"); + vk::Result result = device.createBuffer(&bufferCI, nullptr, &buffer); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create buffer", "VulkanInstance::createBuffer"); } - VkMemoryRequirements2 memReq; - VkBufferMemoryRequirementsInfo2 bufMemReq; - getBufferMemoryRequirements(device, buffer, bufMemReq, memReq); + vk::BufferMemoryRequirementsInfo2 bufMemReq { .buffer = buffer, }; + vk::MemoryRequirements2 memReq = device.getBufferMemoryRequirements2(bufMemReq); - VkMemoryAllocateInfo memoryAI{}; - memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memoryAI.allocationSize = memReq.memoryRequirements.size; - VkMemoryPropertyFlags wantedProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - memoryAI.memoryTypeIndex = findMemoryType(memReq.memoryRequirements.memoryTypeBits, wantedProperties); + vk::MemoryPropertyFlags wantedProperties = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + vk::MemoryAllocateInfo memoryAI { + .allocationSize = memReq.memoryRequirements.size, + .memoryTypeIndex = findMemoryType(memReq.memoryRequirements.memoryTypeBits, wantedProperties), + }; allocator.allocate(memoryAI, memReq, bufferMI); - result = vkBindBufferMemory(device, buffer, bufferMI.memory, bufferMI.offset); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to bind buffer to its memory", "createBuffer"); + result = device.bindBufferMemory(buffer, bufferMI.memory, bufferMI.offset); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to bind buffer to its memory", "VulkanInstance::createBuffer"); } vLog.log0("createBuffer: created and bound buffer of size", memoryAI.allocationSize); } - void VulkanInstance::destroyBuffer(VkBuffer& buffer, MemoryInfo& bufferMemory) { - vkDestroyBuffer(device, buffer, NO_ALLOC); + void VulkanInstance::destroyBuffer(vk::Buffer& buffer, MemoryInfo& bufferMemory) { + device.destroyBuffer(buffer, NO_ALLOC); allocator.free(bufferMemory); buffer = VK_NULL_HANDLE; } @@ -791,316 +638,325 @@ using std::uint32_t; // VERTEX BUFFER template - void VulkanInstance::createVertexBuffer(size_t vertexCount, VkBuffer& vertexBuffer, MemoryInfo& vertexBufferMemory, VkDeviceSize& vertexBufferSize) { + void VulkanInstance::createVertexBuffer(size_t vertexCount, vk::Buffer& vertexBuffer, MemoryInfo& vertexBufferMemory, vk::DeviceSize& vertexBufferSize) { vertexBufferSize = vertexCount * sizeof(VertexT); // create vertex buffer - VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE; + vk::SharingMode sharingMode = vk::SharingMode::eExclusive; std::vector qFamiliesWithAccess; if (qFamilyIndices.transferFamily.has_value()) { // prefer dedicated transfer family qFamiliesWithAccess = { qFamilyIndices.graphicsFamily.value(), qFamilyIndices.transferFamily.value() }; } - createBuffer(vertexBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory , sharingMode, &qFamiliesWithAccess); + createBuffer(vertexBufferSize, vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eVertexBuffer, vk::MemoryPropertyFlagBits::eDeviceLocal, vertexBuffer, vertexBufferMemory , sharingMode, &qFamiliesWithAccess); vLog.log0("createVertexBuffer: Created vertex buffer with size", vertexBufferSize); } - template void VulkanInstance::createVertexBuffer(size_t vertexCount, VkBuffer& vertexBuffer, MemoryInfo& vertexBufferMemory, VkDeviceSize& vertexBufferSize); - template void VulkanInstance::createVertexBuffer(size_t vertexCount, VkBuffer& vertexBuffer, MemoryInfo& vertexBufferMemory, VkDeviceSize& vertexBufferSize); + template void VulkanInstance::createVertexBuffer(size_t vertexCount, vk::Buffer& vertexBuffer, MemoryInfo& vertexBufferMemory, vk::DeviceSize& vertexBufferSize); + template void VulkanInstance::createVertexBuffer(size_t vertexCount, vk::Buffer& vertexBuffer, MemoryInfo& vertexBufferMemory, vk::DeviceSize& vertexBufferSize); // INDEX BUFFER template - void VulkanInstance::createIndexBuffer(size_t indexCount, VkBuffer& indexBuffer, MemoryInfo& indexBufferMemory, VkDeviceSize& indexBufferSize) { + void VulkanInstance::createIndexBuffer(size_t indexCount, vk::Buffer& indexBuffer, MemoryInfo& indexBufferMemory, vk::DeviceSize& indexBufferSize) { indexBufferSize = indexCount * sizeof(T); // create index buffer - VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE; + vk::SharingMode sharingMode = vk::SharingMode::eExclusive; std::vector qFamiliesWithAccess; if (qFamilyIndices.transferFamily.has_value()) { // prefer dedicated transfer family qFamiliesWithAccess = { qFamilyIndices.graphicsFamily.value(), qFamilyIndices.transferFamily.value() }; } - createBuffer(indexBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory, sharingMode, &qFamiliesWithAccess); + createBuffer(indexBufferSize, vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eIndexBuffer, vk::MemoryPropertyFlagBits::eDeviceLocal, indexBuffer, indexBufferMemory, sharingMode, &qFamiliesWithAccess); vLog.log0("createIndexBuffer: Created index buffer with size:", indexBufferSize); } - template void VulkanInstance::createIndexBuffer(size_t indexCount, VkBuffer& indexBuffer, MemoryInfo& indexBufferMemory, VkDeviceSize& indexBufferSize); - template void VulkanInstance::createIndexBuffer(size_t indexCount, VkBuffer& indexBuffer, MemoryInfo& indexBufferMemory, VkDeviceSize& indexBufferSize); + template void VulkanInstance::createIndexBuffer(size_t indexCount, vk::Buffer& indexBuffer, MemoryInfo& indexBufferMemory, vk::DeviceSize& indexBufferSize); + template void VulkanInstance::createIndexBuffer(size_t indexCount, vk::Buffer& indexBuffer, MemoryInfo& indexBufferMemory, vk::DeviceSize& indexBufferSize); // FRAMEBUFFERS - void VulkanInstance::createFramebuffers(std::vector& framebuffers, std::vector& imageViews, VkRenderPass& renderPass) { + void VulkanInstance::createFramebuffers(std::vector& framebuffers, std::vector& imageViews, vk::RenderPass& renderPass, vk::ImageView depthImageView) { framebuffers.resize(scImageViews.size()); - VkFramebufferCreateInfo framebufferCI{}; - framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferCI.renderPass = renderPass; - framebufferCI.width = scExtent.width; - framebufferCI.height = scExtent.height; - framebufferCI.layers = 1; - + vk::FramebufferCreateInfo framebufferCI { + .renderPass = renderPass, + .width = scExtent.width, + .height = scExtent.height, + .layers = 1, + }; + std::vector attachments; for (size_t i = 0; i < framebuffers.size(); i++) { - // TODO include depth image view for 3D - std::vector attachments = { imageViews[i] }; //, depthImageView }; - framebufferCI.pAttachments = attachments.data(); - framebufferCI.attachmentCount = static_cast(attachments.size()); + if (static_cast(depthImageView) != VK_NULL_HANDLE) { + attachments = { imageViews[i] , depthImageView }; + } + else { + attachments = { imageViews[i] }; + } + framebufferCI.setAttachments(attachments); - VkResult result = vkCreateFramebuffer(device, &framebufferCI, nullptr, &framebuffers[i]); - if (result != VK_SUCCESS) { - throw getVkException(result, "Could not create framebuffer", "createFramebuffers_"); + vk::Result result = device.createFramebuffer(&framebufferCI, NO_ALLOC, &framebuffers[i]); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Could not create framebuffer", "VulkanInstance::createFramebuffers"); } } vLog.log0("createFramebuffers: Created", framebuffers.size(), "framebuffers."); } - void VulkanInstance::destroyFramebuffers(std::vector& framebuffers) { + void VulkanInstance::destroyFramebuffers(std::vector& framebuffers) { for (auto& framebuffer : framebuffers) { - vkDestroyFramebuffer(device, framebuffer, nullptr); + device.destroyFramebuffer(framebuffer); } } // TEXTURE SAMPLER - void VulkanInstance::createTextureSampler(VkSampler& sampler) { - VkSamplerCreateInfo samplerCI{}; - samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - // TODO: LINEAR or NEAREST - samplerCI.magFilter = VK_FILTER_LINEAR; - samplerCI.minFilter = VK_FILTER_LINEAR; - samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCI.anisotropyEnable = bool2VkBool(settings.get("anisotropy_enable")); - samplerCI.maxAnisotropy = settings.get("max_anisotropy"); - samplerCI.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - // TODO - samplerCI.unnormalizedCoordinates = VK_FALSE; - samplerCI.compareEnable = VK_FALSE; - samplerCI.compareOp = VK_COMPARE_OP_ALWAYS; - samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCI.mipLodBias = 0.0f; - samplerCI.minLod = 0.0f; - samplerCI.maxLod = 0.0f; + void VulkanInstance::createTextureSampler(vk::Sampler& sampler) { + vk::SamplerCreateInfo samplerCI { + // TODO: LINEAR or NEAREST + .magFilter = vk::Filter::eLinear, + .minFilter = vk::Filter::eLinear, + // TODO + .mipmapMode = vk::SamplerMipmapMode::eLinear, + .addressModeU = vk::SamplerAddressMode::eRepeat, + .addressModeV = vk::SamplerAddressMode::eRepeat, + .addressModeW = vk::SamplerAddressMode::eRepeat, + .mipLodBias = 0.0f, + .anisotropyEnable = bool2VkBool(settings.get("anisotropy_enable")), + .maxAnisotropy = settings.get("max_anisotropy"), + .compareEnable = VK_FALSE, + .compareOp = vk::CompareOp::eAlways, + .minLod = 0.0f, + .maxLod = 0.0f, + .borderColor = vk::BorderColor::eIntOpaqueBlack, + .unnormalizedCoordinates = VK_FALSE, + }; - VkResult result = vkCreateSampler(device, &samplerCI, nullptr, &sampler); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create texture sampler.", "createTextureSampler"); + vk::Result result = device.createSampler(&samplerCI, nullptr, &sampler); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create texture sampler.", "VulkanInstance::createTextureSampler"); } } - void VulkanInstance::destroyTextureSampler(VkSampler& sampler) { - vkDestroySampler(device, sampler, NO_ALLOC); + void VulkanInstance::destroyTextureSampler(vk::Sampler& sampler) { + device.destroySampler(sampler, NO_ALLOC); sampler = VK_NULL_HANDLE; } // PUBLIC INTERFACE: IMAGE UTILITY - void VulkanInstance::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkImage& image, MemoryInfo& imageMI) { - VkImageCreateInfo imageCI{}; - imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCI.imageType = VK_IMAGE_TYPE_2D; - imageCI.extent.width = static_cast(width); - imageCI.extent.height = static_cast(height); - imageCI.extent.depth = 1; - imageCI.mipLevels = 1; - imageCI.arrayLayers = 1; - imageCI.format = format; - // use linear when direct texel access is needed - imageCI.tiling = tiling; - imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCI.usage = usage; - imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageCI.samples = VK_SAMPLE_COUNT_1_BIT; - /* imageCI.flags = 0; */ - VkResult result = vkCreateImage(device, &imageCI, NO_ALLOC, &image); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create image", "createImage"); + void VulkanInstance::createImage(uint32_t width, uint32_t height, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags memoryProperties, vk::Image& image, MemoryInfo& imageMI) { + vk::ImageCreateInfo imageCI { + .imageType = vk::ImageType::e2D, + .format = format, + .extent { + .width = width, + .height = height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = vk::SampleCountFlagBits::e1, + // use linear when direct texel access is needed + .tiling = tiling, + .usage = usage, + .sharingMode = vk::SharingMode::eExclusive, + .initialLayout = vk::ImageLayout::eUndefined, + /* .flags = 0, */ + }; + vk::Result result = device.createImage(&imageCI, NO_ALLOC, &image); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create image", "VulkanInstance::createImage"); } - VkMemoryRequirements2 memReq; - VkImageMemoryRequirementsInfo2 imMemReq; - getImageMemoryRequirements(device, image, imMemReq, memReq); + vk::ImageMemoryRequirementsInfo2 imMemReq { .image = image }; + vk::MemoryRequirements2 memReq = device.getImageMemoryRequirements2(imMemReq); - VkMemoryAllocateInfo memoryAI{}; - memoryAI.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memoryAI.allocationSize = memReq.memoryRequirements.size; - memoryAI.memoryTypeIndex = findMemoryType(memReq.memoryRequirements.memoryTypeBits, memoryProperties); + vk::MemoryAllocateInfo memoryAI { + .allocationSize = memReq.memoryRequirements.size, + .memoryTypeIndex = findMemoryType(memReq.memoryRequirements.memoryTypeBits, memoryProperties), + }; allocator.allocate(memoryAI, memReq, imageMI); - result = vkBindImageMemory(device, image, imageMI.memory, imageMI.offset); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to bind image to its memory", "createImage"); + result = device.bindImageMemory(image, imageMI.memory, imageMI.offset); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to bind image to its memory", "VulkanInstance::createImage"); } vLog.log0("createImage: created and bound image of size", memoryAI.allocationSize); } - void VulkanInstance::destroyImage(VkImage& image, MemoryInfo& imageMemory) { - vkDestroyImage(device, image, NO_ALLOC); + void VulkanInstance::destroyImage(vk::Image& image, MemoryInfo& imageMemory) { + device.destroyImage(image, NO_ALLOC); allocator.free(imageMemory); image = VK_NULL_HANDLE; } // IMAGE VIEW - void VulkanInstance::createImageView(VkFormat format, VkImage& image, VkImageView& imageView, VkImageAspectFlags aspectFlags) { - VkImageViewCreateInfo imageViewCI{}; - imageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D; - imageViewCI.format = format; - imageViewCI.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCI.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCI.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCI.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCI.subresourceRange.aspectMask = aspectFlags; - imageViewCI.subresourceRange.baseMipLevel = 0; - imageViewCI.subresourceRange.levelCount = 1; - imageViewCI.subresourceRange.baseArrayLayer = 0; - imageViewCI.subresourceRange.layerCount = 1; - imageViewCI.image = image; - VkResult result = vkCreateImageView(device, &imageViewCI, nullptr, &imageView); - if (result != VK_SUCCESS) { - throw getVkException(result, "Could not create image view", "createImageViews"); + void VulkanInstance::createImageView(vk::Format format, vk::Image& image, vk::ImageView& imageView, vk::ImageAspectFlags aspectFlags) { + vk::ImageViewCreateInfo imageViewCI { + .image = image, + .viewType = vk::ImageViewType::e2D, + .format = format, + .components { + .r = vk::ComponentSwizzle::eIdentity, + .g = vk::ComponentSwizzle::eIdentity, + .b = vk::ComponentSwizzle::eIdentity, + .a = vk::ComponentSwizzle::eIdentity, + }, + .subresourceRange { + .aspectMask = aspectFlags, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + vk::Result result = device.createImageView(&imageViewCI, NO_ALLOC, &imageView); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Could not create image view", "VulkanInstance::createImageViews"); } } - void VulkanInstance::destroyImageView(VkImageView& imageView) { - vkDestroyImageView(device, imageView, NO_ALLOC); + void VulkanInstance::destroyImageView(vk::ImageView& imageView) { + device.destroyImageView(imageView, NO_ALLOC); imageView = VK_NULL_HANDLE; } - void VulkanInstance::copyBufferToImage(VkBuffer buffer, VkImage image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height) { - VkCommandBuffer cmdBuffer = beginSingleTimeCommands(POOL_TRANSFER); - VkBufferImageCopy region{}; - region.bufferOffset = NO_OFFSET; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.mipLevel = 0; - region.imageSubresource.baseArrayLayer = 0; - region.imageSubresource.layerCount = 1; - - region.imageOffset = { offsetX, offsetY, 0 }; - region.imageExtent = { width, height, 1 }; - const uint32_t regionCount = 1; - vkCmdCopyBufferToImage(cmdBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regionCount, ®ion); + void VulkanInstance::copyBufferToImage(vk::Buffer buffer, vk::Image image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height) { + vk::CommandBuffer cmdBuffer = beginSingleTimeCommands(POOL_TRANSFER); + vk::BufferImageCopy region { + .bufferOffset = NO_OFFSET, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = { offsetX, offsetY, 0 }, + .imageExtent = { width, height, 1 }, + }; + cmdBuffer.copyBufferToImage(buffer, image, vk::ImageLayout::eTransferDstOptimal, region); endSingleTimeCommands(cmdBuffer, POOL_TRANSFER); } - void VulkanInstance::copyImageToImage(VkCommandBuffer& cmdBuffer, VkImage srcImage, VkImage dstImage, VkExtent2D extent) { - VkImageCopy region{}; - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.srcSubresource.mipLevel = 0; - region.srcSubresource.baseArrayLayer = 0; - region.srcSubresource.layerCount = 1; - - region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.dstSubresource.mipLevel = 0; - region.dstSubresource.baseArrayLayer = 0; - region.dstSubresource.layerCount = 1; - - /* std::array offsets; */ - /* offsets[0] = { 0, 0, 0 }; */ - /* offsets[1] = { 0, 0, 0 }; */ - region.srcOffset = { 0, 0, 0 }; - region.dstOffset = { 0, 0, 0 }; - region.extent = { extent.width, extent.height, 1 }; - const uint32_t regionCount = 1; - vkCmdCopyImage(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regionCount, ®ion); + void VulkanInstance::copyImageToImage(vk::CommandBuffer& cmdBuffer, vk::Image srcImage, vk::Image dstImage, vk::Extent2D extent) { + vk::ImageCopy region { + .srcSubresource { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .srcOffset = { 0, 0, 0 }, + .dstSubresource { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .dstOffset = { 0, 0, 0 }, + .extent = { extent.width, extent.height, 1 }, + }; + cmdBuffer.copyImage(srcImage, vk::ImageLayout::eTransferSrcOptimal, dstImage, vk::ImageLayout::eTransferDstOptimal, region); } - bool hasStencilComponent(VkFormat format) { - return format == VK_FORMAT_D32_SFLOAT_S8_UINT or format == VK_FORMAT_D24_UNORM_S8_UINT; + bool hasStencilComponent(vk::Format format) { + return format == vk::Format::eD32SfloatS8Uint or format == vk::Format::eD24UnormS8Uint; } - void VulkanInstance::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandBuffer* cmdBuffer) { - VkImageMemoryBarrier2 barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - // not using barrier for queue famlily ownership transfer - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - barrier.srcAccessMask = 0; - barrier.dstAccessMask = 0; + void VulkanInstance::transitionImageLayout(vk::Image image, vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::CommandBuffer* cmdBuffer) { + vk::ImageMemoryBarrier2 barrier { + .srcAccessMask = NO_ACC_2_FLAGS, + .dstAccessMask = NO_ACC_2_FLAGS, + .oldLayout = oldLayout, + .newLayout = newLayout, + // not using barrier for queue famlily ownership transfer + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; InstanceCommandPool commandPool; - if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED and - newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (oldLayout == vk::ImageLayout::eUndefined and + newLayout == vk::ImageLayout::eDepthStencilAttachmentOptimal) { + barrier.srcAccessMask = NO_ACC_2_FLAGS; + barrier.dstAccessMask = vk::AccessFlagBits2::eDepthStencilAttachmentRead | vk::AccessFlagBits2::eDepthStencilAttachmentWrite; + barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eDepth; if (hasStencilComponent(format)) { - barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + barrier.subresourceRange.aspectMask |= vk::ImageAspectFlagBits::eStencil; } - barrier.srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - barrier.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eEarlyFragmentTests; commandPool = POOL_GRAPHICS; } - else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED and - newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + else if (oldLayout == vk::ImageLayout::eUndefined and + newLayout == vk::ImageLayout::eTransferDstOptimal) { + barrier.srcAccessMask = NO_ACC_2_FLAGS; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - barrier.srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - barrier.dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; commandPool = POOL_TRANSFER; } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL and - newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and + newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - barrier.srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - barrier.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; commandPool = POOL_GRAPHICS; } - else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL and - newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + else if (oldLayout == vk::ImageLayout::eShaderReadOnlyOptimal and + newLayout == vk::ImageLayout::eTransferDstOptimal) { + barrier.srcAccessMask = vk::AccessFlagBits2::eShaderRead; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - barrier.srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - barrier.dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eFragmentShader; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; commandPool = POOL_GRAPHICS; } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL and - newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and + newLayout == vk::ImageLayout::ePresentSrcKHR) { + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eMemoryRead; - barrier.srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - barrier.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput; commandPool = POOL_GRAPHICS; } else { - throw VkUserError(std::string("transitionImageLayout: Unsupported layout transition") + STR_VK_IMAGE_LAYOUT(oldLayout) + "->" + STR_VK_IMAGE_LAYOUT(newLayout), "transitionImageLayout");; + throw VkUserError(std::string("Unsupported layout transition") + ::toString(oldLayout) + "->" + ::toString(newLayout), "VulkanInstance::transitionImageLayout"); } // if not provided, get a single time command buffer - VkCommandBuffer cmdBuffer_; + vk::CommandBuffer cmdBuffer_; if (cmdBuffer == nullptr) { cmdBuffer_ = beginSingleTimeCommands(commandPool); } else { cmdBuffer_ = *cmdBuffer; } - VkDependencyInfo depI = getDepInfo(barrier); - vkCmdPipelineBarrier2(cmdBuffer_, &depI); + vk::DependencyInfo depI = getDepInfo(barrier); + cmdBuffer_.pipelineBarrier2(depI); if (cmdBuffer == nullptr) { endSingleTimeCommands(cmdBuffer_, commandPool); @@ -1110,7 +966,7 @@ using std::uint32_t; // // STATIC: DEBUG LOG // - gz::Log VulkanInstance::vLog("vulkan.log", true, true, "Vulkan", VULKAN_MESSAGE_PREFIX_COLOR, true, VULKAN_MESSAGE_TIME_COLOR); + gz::Log VulkanInstance::vLog("vulkan.log", true, true, "Vulkan", settings::VULKAN_MESSAGE_PREFIX_COLOR, true, settings::VULKAN_MESSAGE_TIME_COLOR); VKAPI_ATTR VkBool32 VKAPI_CALL VulkanInstance::debugLog( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverety, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -1137,19 +993,18 @@ using std::uint32_t; type = "None:"; colors.push_back(gz::Color::WHITE); } - // color for second keyword / whole message if not validation message switch(messageSeverety) { case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: colors.push_back(gz::Color::RESET); break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: colors.push_back(gz::Color::WHITE); break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: colors.push_back(gz::Color::BG_YELLOW); break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: colors.push_back(gz::Color::BG_RED); break; default: @@ -1161,7 +1016,7 @@ using std::uint32_t; std::string_view messageIdName(pCallbackData->pMessageIdName); // extra differenciation between different validation messages // is validation or performance message: get type from brackets, print owner of any pointers - if (messageType & (VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT)) { + if (messageType & (VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT)) { // if cant be found npos + 1 = 0 size_t startAt = message.find(']') + 1; if (messageIdName.starts_with("UNASSIGNED-DEBUG-PRINTF")) { @@ -1200,7 +1055,7 @@ using std::uint32_t; vLog.clog(colors, std::move(type), message); } lastColorWhite = !lastColorWhite; - if (throwExceptionOnValidationError and messageSeverety == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + if (settings::throwExceptionOnValidationError and messageSeverety == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { throw VkException("Validation error:" + std::string(message), "VulkanInstance::debugLog"); } return VK_FALSE; @@ -1214,94 +1069,123 @@ using std::uint32_t; // INSTANCE void VulkanInstance::createInstance() { - VkApplicationInfo appInfo{}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pEngineName = "Glowzwiebel Engine"; - appInfo.pApplicationName = "Hallo Dreieck"; - appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.apiVersion = VK_API_VERSION_1_3; + vk::ApplicationInfo appInfo { + .pApplicationName = "Glowzwiebels Vulkan Project", + .applicationVersion = VK_MAKE_VERSION(1, 0, 0), + .pEngineName = "Glowzwiebel Engine", + .apiVersion = VK_API_VERSION_1_3, + }; - VkInstanceCreateInfo instanceCI{}; - instanceCI.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instanceCI.pApplicationInfo = &appInfo; - instanceCI.pNext = &debugUtilsMessengerCI; - instanceCI.flags = 0; - instanceCI.ppEnabledExtensionNames = instanceExtensions.data(); - instanceCI.enabledExtensionCount = instanceExtensions.size(); + VkDebugUtilsMessengerCreateInfoEXT debugCI = static_cast(debugUtilsMessengerCI); + vk::InstanceCreateInfo instanceCI { + .pNext = &debugCI, + .pApplicationInfo = &appInfo, + }; if (enableValidationLayers) { if (!validationLayersSupported()) { - throw std::runtime_error("Validation layers enabled but not available."); + throw VkException("Validation layers enabled but not available.", "VulkanInstance::createInstance"); } - instanceCI.enabledLayerCount = static_cast(validationLayers.size()); - instanceCI.ppEnabledLayerNames = validationLayers.data(); - } - else { - instanceCI.enabledLayerCount = 0; - instanceCI.ppEnabledLayerNames = nullptr; + instanceCI.setPEnabledLayerNames(settings::validationLayers); } - std::vector requiredExtensions = getRequiredExtensions(); - instanceCI.enabledExtensionCount = static_cast(requiredExtensions.size()); - instanceCI.ppEnabledExtensionNames = requiredExtensions.data();; + std::vector requiredInstanceExtensions = getRequiredInstanceExtensions(); + instanceCI.setPEnabledExtensionNames(requiredInstanceExtensions); // log requiredExtensions std::string message; message.reserve(80); message += "Required extensions ("; message += std::to_string(instanceCI.enabledExtensionCount) + ')'; - for (uint32_t i = 0; i < requiredExtensions.size(); i++) { + for (uint32_t i = 0; i < requiredInstanceExtensions.size(); i++) { message += "\n\t"; - message += std::to_string(i + 1) + ": " + requiredExtensions[i]; + message += std::to_string(i + 1) + ": " + requiredInstanceExtensions[i]; } - vLog.log3(message); + vLog.log2(message); - VkResult result = vkCreateInstance(&instanceCI, nullptr, &instance); - if (result != VK_SUCCESS) { - vLog.log3("Failed to create instance.", "VkResult:", STR_VK_RESULT(result)); - throw std::runtime_error("Failed to create instance."); + vk::Result result = vk::createInstance(&instanceCI, NO_ALLOC, &instance); + if (result != vk::Result::eSuccess) { + vLog.error("Failed to create instance.", "VkResult:", result); + throw getVkException(result, "Failed to create instance", "VulkanInstance::createInstance"); } - uint32_t extensionCount = 0; - vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); // get count - std::vector extensions(extensionCount); - vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); + auto [result2, extensions] = vk::enumerateInstanceExtensionProperties(); + if (result2 != vk::Result::eSuccess) { + throw getVkException(result, "Failed to enumerate instance extension properties", "VulkanInstance::createInstance"); + } // log available extensions message = "Available extensions ("; - message += std::to_string(extensionCount) + "):"; + message += gz::toString(extensions.size()) + "):"; for (uint32_t i = 0; i < extensions.size(); i++) { message += "\n\t"; - message += std::to_string(i + 1) + ": " + extensions[i].extensionName; + message += gz::toString(i + 1) + ": " + gz::toString(extensions[i].extensionName); } - vLog.log3(message); + vLog.log2(message); - if (!checkRequiredExtensionsAvailable(requiredExtensions, extensions)) { - throw std::runtime_error("Not all required extensions are available."); + if (!areExtensionsAvailable(requiredInstanceExtensions, extensions)) { + throw VkException("Not all required extensions are available.", "VulkanInstance::createInstance"); } } + std::vector VulkanInstance::getRequiredInstanceExtensions() const { + uint32_t glfwExtensionCount = 0; + const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); + std::vector requiredExtensions(glfwExtensions, glfwExtensions + glfwExtensionCount); + + if (enableValidationLayers) { + requiredExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + requiredExtensions.push_back(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME); + } + return requiredExtensions; + } + + + // check if validation layers are supported/installed + bool VulkanInstance::validationLayersSupported() { + std::vector availableLayers; + vk::Result result; + std::tie(result, availableLayers) = vk::enumerateInstanceLayerProperties(); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to enumerate available validation layers", "VulkanInstance::validationLayersSupported"); + } + + bool layerAvailable; + for (const char* requiredLayer : settings::validationLayers) { + layerAvailable = false; + for (const auto& layerProperties : availableLayers) { + if (strcmp(requiredLayer, layerProperties.layerName) == 0) { + layerAvailable = true; + break; + } + } + if (!layerAvailable) { return false; } + } + return true; + } + + -// PHYSICAL DEVICE - PhysicalDeviceFeatures VulkanInstance::getRequiredFeatures() const { +// PHYSICAL DEVICE: SELECTION PROCESS + // FEATURES + PhysicalDeviceFeatures VulkanInstance::getRequiredDeviceFeatures() const { PhysicalDeviceFeatures requiredFeatures; requiredFeatures.f13.synchronization2 = VK_TRUE; return requiredFeatures; } - void VulkanInstance::selectPhysicalDevice() { - uint32_t deviceCount = 0; - vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); - - if (deviceCount == 0) { - vLog.error("Could not find any GPU."); - throw std::runtime_error("Could not find any GPU."); + auto [result, devices] = instance.enumeratePhysicalDevices(); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to enumerate physical devices", "VulkanInstance::selectPhysicalDevice"); + } + + if (devices.size() == 0) { + vLog.error("Could not find any GPU."); + throw VkException("Could not find any GPU.", "VulkanInstance::selectPhysicalDevice"); } - std::vector devices(deviceCount); - vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); // find best gpu std::vector deviceScores; @@ -1315,10 +1199,15 @@ using std::uint32_t; } physicalDevice = devices[bestGPUIndex]; - vkGetPhysicalDeviceProperties(physicalDevice, &phDevProperties); + // initialize members + phDevProperties = physicalDevice.getProperties2(); vkGetPhysicalDeviceFeatures2(physicalDevice, &phDevFeatures.f); + /* phDevFeatures.f = physicalDevice.getFeatures2(&phDevFeatures.f); */ + phDevMemProperties = physicalDevice.getMemoryProperties2(); qFamilyIndices = findQueueFamilies(physicalDevice); - vLog("Selected GPU:", phDevProperties.deviceName, "with the following queue family indices:", qFamilyIndices); + depthFormat = findSupportedFormat({ vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint }, vk::ImageTiling::eOptimal, vk::FormatFeatureFlagBits::eDepthStencilAttachment); + + vLog.log3("selectPhysicalDevice: Selected GPU:", phDevProperties.properties.deviceName); } @@ -1328,27 +1217,26 @@ using std::uint32_t; const unsigned int SCORE_HAS_ALL_QUEUE_FAMILIES = 100; const unsigned int SCORE_HAS_FEATURE = 100; - unsigned int VulkanInstance::rateDevice(VkPhysicalDevice device) { + unsigned int VulkanInstance::rateDevice(vk::PhysicalDevice phDevice) { unsigned int score; // rate type - VkPhysicalDeviceProperties properties{}; - vkGetPhysicalDeviceProperties(device, &properties); - switch(properties.deviceType) { - case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + vk::PhysicalDeviceProperties2 properties = phDevice.getProperties2(); + switch(properties.properties.deviceType) { + case vk::PhysicalDeviceType::eDiscreteGpu: score = SCORE_DISCRETE_GPU; break; - case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + case vk::PhysicalDeviceType::eIntegratedGpu: score = SCORE_INTEGRATED_GPU; break; - case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: + case vk::PhysicalDeviceType::eVirtualGpu: score = SCORE_VIRTUAL_GPU; break; default: return 0; } - qFamilyIndices = findQueueFamilies(device); + qFamilyIndices = findQueueFamilies(phDevice); // has needed queue families if (qFamilyIndices.hasAllValues()) { score += SCORE_HAS_ALL_QUEUE_FAMILIES; @@ -1357,16 +1245,22 @@ using std::uint32_t; return 0; } - // supports all extensions - if (!deviceExtensionsSupported(device)) { + // supports all extensions (global var) + vk::Result result; + std::vector availableExtensions; + std::tie(result, availableExtensions) = phDevice.enumerateDeviceExtensionProperties(); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to enumerate device extension properties", "VulkanInstance::rateDevice"); + } + if (!areExtensionsAvailable(settings::deviceExtensions, availableExtensions)) { return 0; } // supports all features - PhysicalDeviceFeatures requiredFeatures = getRequiredFeatures(); + PhysicalDeviceFeatures requiredFeatures = getRequiredDeviceFeatures(); PhysicalDeviceFeatures features; - vLog("features sType", STR_VK_STRUCTURE_TYPE(features.f.sType)); - vkGetPhysicalDeviceFeatures2(device, &features.f); + /* features.f = phDevice.getFeatures2(features.f); */ + vkGetPhysicalDeviceFeatures2(phDevice, &features.f); if (!features.requiredFeaturesAvailable(requiredFeatures)) { return 0; } @@ -1374,38 +1268,35 @@ using std::uint32_t; if (features.f.features.samplerAnisotropy == VK_TRUE) { score += SCORE_HAS_FEATURE; } // swap chain support - SwapChainSupport scDetails = querySwapChainSupport(device); + SwapChainSupport scDetails = querySwapChainSupport(phDevice); if (scDetails.formats.empty() or scDetails.presentModes.empty()) { return 0; } // rate memory - VkPhysicalDeviceMemoryProperties memProperties{}; - vkGetPhysicalDeviceMemoryProperties(device, &memProperties); - for (uint32_t i = 0; i < memProperties.memoryHeapCount; i++) { - score += memProperties.memoryHeaps[i].size / 1e6; + vk::PhysicalDeviceMemoryProperties2 memProperties = phDevice.getMemoryProperties2(); + for (uint32_t i = 0; i < memProperties.memoryProperties.memoryHeapCount; i++) { + score += memProperties.memoryProperties.memoryHeaps[i].size / 1e6; } - - vLog("rateDevice: GPU: ", properties.deviceName, " - Score: ", score); + vLog("rateDevice: GPU: ", properties.properties.deviceName, " - Score: ", score); return score; } - VkFormat VulkanInstance::findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) { - for (const VkFormat& format : candidates) { - VkFormatProperties formatProperties; - vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties); - if (tiling == VK_IMAGE_TILING_LINEAR and - (formatProperties.linearTilingFeatures & features) == features) { + vk::Format VulkanInstance::findSupportedFormat(const std::vector& candidates, vk::ImageTiling tiling, vk::FormatFeatureFlags features) { + for (const vk::Format& format : candidates) { + vk::FormatProperties2 formatProperties = physicalDevice.getFormatProperties2(format); + if (tiling == vk::ImageTiling::eLinear and + (formatProperties.formatProperties.linearTilingFeatures & features) == features) { return format; } - else if (tiling == VK_IMAGE_TILING_OPTIMAL and - (formatProperties.optimalTilingFeatures & features) == features) { + else if (tiling == vk::ImageTiling::eOptimal and + (formatProperties.formatProperties.optimalTilingFeatures & features) == features) { return format; } } - throw VkException(std::string("Could not find a suitable format. tiling: ") + STR_VK_IMAGE_TILING(tiling) + ".", "findSupportedFormat"); + throw VkException(std::string("Could not find a suitable format. tiling: ") + ::toString(tiling) + ".", "VulkanInstance::findSupportedFormat"); } @@ -1414,40 +1305,38 @@ using std::uint32_t; // IMPORTANT: EDIT DOCUMENTATION WHEN ADDING/CHANGING VALUES // anisotropic filtering settings.setAllowedValues("anisotropy_enable", { false, vkBool2Bool(phDevFeatures.f.features.samplerAnisotropy) }, gz::SM_LIST); - settings.setAllowedValues("max_anisotropy", { 1.0f, phDevProperties.limits.maxSamplerAnisotropy }, gz::SM_RANGE); + settings.setAllowedValues("max_anisotropy", { 1.0f, phDevProperties.properties.limits.maxSamplerAnisotropy }, gz::SM_RANGE); settings.setAllowedValues("max_frames_in_flight", { 1, 4 }, SM_RANGE); } // QUEUE - QueueFamilyIndices VulkanInstance::findQueueFamilies(VkPhysicalDevice device) { + QueueFamilyIndices VulkanInstance::findQueueFamilies(vk::PhysicalDevice phDevice) { QueueFamilyIndices indices; - uint32_t qFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &qFamilyCount, nullptr); - std::vector qFamilies(qFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(device, &qFamilyCount, qFamilies.data()); - vLog("findQueueFamilies: found", qFamilyCount, "queue families:"); + std::vector qFamilies = phDevice.getQueueFamilyProperties2(); + vLog.log1("findQueueFamilies: found", qFamilies.size(), "queue families:"); - VkBool32 presentSupport = false; - for (unsigned int i = 0; i < qFamilyCount; i++) { + vk::Bool32 presentSupport = false; + vk::Result result; + for (unsigned int i = 0; i < qFamilies.size(); i++) { // check for queue with graphic capabilities - if (qFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + if (qFamilies[i].queueFamilyProperties.queueFlags & vk::QueueFlagBits::eGraphics) { indices.graphicsFamily = i; } - else if (qFamilies[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { // only transfer, not graphics + else if (qFamilies[i].queueFamilyProperties.queueFlags & vk::QueueFlagBits::eTransfer) { // only transfer, not graphics indices.transferFamily = i; } // check for surface support - vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); + std::tie(result, presentSupport) = phDevice.getSurfaceSupportKHR(i, surface); if (presentSupport == VK_TRUE) { indices.presentFamily = i; } - vLog("findQueueFamilies:", i, "-", qFamilies[i].queueFlags); + vLog.log1("findQueueFamilies:", i, "-", qFamilies[i].queueFamilyProperties.queueFlags); if (indices.hasAllValues()) { - vLog("findQueueFamilies: Found all wanted families."); + vLog.log1("findQueueFamilies: Found all wanted families."); break; } } @@ -1465,41 +1354,37 @@ using std::uint32_t; qFamiliyIndicesSet.insert(qFamilyIndices.transferFamily.value()); } - std::vector deviceQueueCI; + std::vector deviceQueueCI; for (uint32_t index : qFamiliyIndicesSet) { - deviceQueueCI.push_back(VkDeviceQueueCreateInfo()); - deviceQueueCI.back().sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + deviceQueueCI.push_back(vk::DeviceQueueCreateInfo()); deviceQueueCI.back().queueFamilyIndex = index; deviceQueueCI.back().queueCount = 1; float qPriority = 1.0f; deviceQueueCI.back().pQueuePriorities = &qPriority; } - PhysicalDeviceFeatures enabledFeatures = getRequiredFeatures(); + PhysicalDeviceFeatures enabledFeatures = getRequiredDeviceFeatures(); // optional features enabledFeatures.f.features.samplerAnisotropy = bool2VkBool(settings.getOr("anisotropy_enable", false)); - VkDeviceCreateInfo deviceCI{}; - deviceCI.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceCI.pQueueCreateInfos = deviceQueueCI.data(); - deviceCI.queueCreateInfoCount = static_cast(deviceQueueCI.size()); - deviceCI.pNext = &enabledFeatures.f; - /* deviceCI.pEnabledFeatures = &deviceFeatures.f; */ - deviceCI.enabledExtensionCount = static_cast(extensions.size()); - deviceCI.ppEnabledExtensionNames = extensions.data(); + vk::DeviceCreateInfo deviceCI { + .pNext = &enabledFeatures.f, + /* .pEnabledFeatures = &deviceFeatures.f, */ + }; + deviceCI.setQueueCreateInfos(deviceQueueCI); + deviceCI.setPEnabledExtensionNames(settings::deviceExtensions); - VkResult result = vkCreateDevice(physicalDevice, &deviceCI, nullptr, &device); - if (result != VK_SUCCESS) { - vLog.error("createLogicalDevice: Failed to create logical device.", "VkResult:", STR_VK_RESULT(result)); - throw std::runtime_error("createLogicalDevice: Failed to create logical device."); + vk::Result result = physicalDevice.createDevice(&deviceCI, nullptr, &device); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create logical device.", "VulkanInstance::createLogicalDevice"); } // get handles uint32_t index = 0; - vkGetDeviceQueue(device, qFamilyIndices.graphicsFamily.value(), index, &graphicsQ); - vkGetDeviceQueue(device, qFamilyIndices.presentFamily.value(), index, &presentQ); + graphicsQ = device.getQueue(qFamilyIndices.graphicsFamily.value(), index); + presentQ = device.getQueue(qFamilyIndices.presentFamily.value(), index); if (qFamilyIndices.transferFamily.has_value()) { - vkGetDeviceQueue(device, qFamilyIndices.transferFamily.value(), index, &transferQ); + transferQ = device.getQueue(qFamilyIndices.transferFamily.value(), index); } else { transferQ = graphicsQ; @@ -1510,38 +1395,48 @@ using std::uint32_t; // SURFACE void VulkanInstance::createSurface() { - VkResult result = glfwCreateWindowSurface(instance, window, nullptr, &surface); + VkSurfaceKHR surface2 = surface; + VkResult result = glfwCreateWindowSurface(static_cast(instance), window, nullptr, &surface2); + surface = surface2; if (result != VK_SUCCESS) { - vLog.error("createSurface: Failed to create window surface.", "VkResult:", STR_VK_RESULT(result)); - throw std::runtime_error("createSurface: Failed to create window surface."); + throw getVkException(vk::Result(result), "Failed to create window surface.", "VulkanInstance::createSurface"); } } // SWAP CHAIN - SwapChainSupport VulkanInstance::querySwapChainSupport(VkPhysicalDevice physicalDevice) { + SwapChainSupport VulkanInstance::querySwapChainSupport(vk::PhysicalDevice physicalDevice) { SwapChainSupport scDetails{}; + vk::Result result; - uint32_t formatCount; - vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr); - scDetails.formats.resize(formatCount); - vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, scDetails.formats.data()); + vk::PhysicalDeviceSurfaceInfo2KHR surfaceI { .surface = surface }; + std::tie(result, scDetails.formats) = physicalDevice.getSurfaceFormats2KHR(surfaceI); + if (result != vk::Result::eSuccess) { + throw getVkException(vk::Result(result), "Failed get surface formats.", "VulkanInstance::querySwapChainSupport"); + } - uint32_t presentModeCount; - vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr); - scDetails.presentModes.resize(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, scDetails.presentModes.data()); - - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &scDetails.capabilities); + std::tie(result, scDetails.presentModes) = physicalDevice.getSurfacePresentModesKHR(surface); + if (result != vk::Result::eSuccess) { + throw getVkException(vk::Result(result), "Failed get surface present modes.", "VulkanInstance::querySwapChainSupport"); + } + std::tie(result, scDetails.capabilities) = physicalDevice.getSurfaceCapabilities2KHR(surfaceI); + if (result != vk::Result::eSuccess) { + throw getVkException(vk::Result(result), "Failed get surface capabilities.", "VulkanInstance::querySwapChainSupport"); + } return scDetails; } - VkSurfaceFormatKHR VulkanInstance::selectSwapChainSurfaceFormat(const std::vector& availableFormats) { + vk::SurfaceFormat2KHR VulkanInstance::selectSwapChainSurfaceFormat(const std::vector& availableFormats) { vLog.log0("selectSwapChainSurfaceFormat:", availableFormats.size(), "formats available."); + // TODO REMOVE for (const auto& format : availableFormats) { - if (format.format == VK_FORMAT_B8G8R8A8_SRGB and format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + vLog.log0("selectSwapChainSurfaceFormat: format:", format.surfaceFormat.format, "with color space:", format.surfaceFormat.colorSpace); + } + + for (const auto& format : availableFormats) { + if (format.surfaceFormat.format == vk::Format::eB8G8R8A8Srgb and format.surfaceFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { return format; } } @@ -1549,85 +1444,86 @@ using std::uint32_t; } - VkPresentModeKHR VulkanInstance::selectSwapChainPresentMode(const std::vector& availableModes) { + vk::PresentModeKHR VulkanInstance::selectSwapChainPresentMode(const std::vector& availableModes) { for (const auto& mode : availableModes) { - if (mode == VK_PRESENT_MODE_MAILBOX_KHR) { + if (mode == vk::PresentModeKHR::eMailbox) { return mode; } } - return VK_PRESENT_MODE_FIFO_KHR; + return vk::PresentModeKHR::eFifo; } - VkExtent2D VulkanInstance::selectSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) { + vk::Extent2D VulkanInstance::selectSwapExtent(const vk::SurfaceCapabilities2KHR& capabilities) { // if width = max(uint32_t) then surface size will be determined by a swapchain targeting it - if (capabilities.currentExtent.width == std::numeric_limits::max()) { + if (capabilities.surfaceCapabilities.currentExtent.width == std::numeric_limits::max()) { int width, height; glfwGetFramebufferSize(window, &width, &height); - VkExtent2D actualExtent {}; - actualExtent.width = std::clamp(static_cast(width), capabilities.minImageExtent.width, capabilities.maxImageExtent.width); - actualExtent.height = std::clamp(static_cast(height), capabilities.minImageExtent.height, capabilities.maxImageExtent.height); + vk::Extent2D actualExtent { + .width = std::clamp(static_cast(width), capabilities.surfaceCapabilities.minImageExtent.width, capabilities.surfaceCapabilities.maxImageExtent.width), + .height = std::clamp(static_cast(height), capabilities.surfaceCapabilities.minImageExtent.height, capabilities.surfaceCapabilities.maxImageExtent.height), + }; return actualExtent; } else { - return capabilities.currentExtent; + return capabilities.surfaceCapabilities.currentExtent; } } void VulkanInstance::createSwapChain() { SwapChainSupport scDetails = querySwapChainSupport(physicalDevice); - VkSurfaceFormatKHR surfaceFormat = selectSwapChainSurfaceFormat(scDetails.formats); + vk::SurfaceFormat2KHR surfaceFormat = selectSwapChainSurfaceFormat(scDetails.formats); - uint32_t imageCount = scDetails.capabilities.minImageCount + 1; + uint32_t imageCount = scDetails.capabilities.surfaceCapabilities.minImageCount + 1; // maxImageCount = 0 -> no max - if (scDetails.capabilities.maxImageCount > 0 and imageCount < scDetails.capabilities.maxImageCount) { - imageCount = scDetails.capabilities.maxImageCount; + if (scDetails.capabilities.surfaceCapabilities.maxImageCount > 0 and imageCount < scDetails.capabilities.surfaceCapabilities.maxImageCount) { + imageCount = scDetails.capabilities.surfaceCapabilities.maxImageCount; } - scImageFormat = surfaceFormat.format; + scImageFormat = surfaceFormat.surfaceFormat.format; scExtent = selectSwapExtent(scDetails.capabilities); - VkSwapchainCreateInfoKHR swapChainCI{}; - swapChainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapChainCI.surface = surface; - swapChainCI.minImageCount = imageCount; - swapChainCI.imageFormat = scImageFormat; - swapChainCI.imageColorSpace = surfaceFormat.colorSpace; - swapChainCI.imageExtent = scExtent; - swapChainCI.imageArrayLayers = 1; - // if postProcessing: VK_IMAGE_USAGE_TRANSFER_DST_BIT - swapChainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + vk::SwapchainCreateInfoKHR swapChainCI { + .surface = surface, + .minImageCount = imageCount, + .imageFormat = scImageFormat, + .imageColorSpace = surfaceFormat.surfaceFormat.colorSpace, + .imageExtent = scExtent, + .imageArrayLayers = 1, + // if postProcessing: vk::ImageUsageFlagBits::eTransferDst + .imageUsage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst, + .preTransform = scDetails.capabilities.surfaceCapabilities.currentTransform, + .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque, + .presentMode = selectSwapChainPresentMode(scDetails.presentModes), + .clipped = VK_TRUE, + .oldSwapchain = VK_NULL_HANDLE, + }; /* QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice); */ // must live until vkCreateSwapchainKHR std::vector qIndices; if (qFamilyIndices.graphicsFamily.value() != qFamilyIndices.presentFamily.value()) { - swapChainCI.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - qIndices = { qFamilyIndices.graphicsFamily.value(), qFamilyIndices.presentFamily.value() }; - swapChainCI.queueFamilyIndexCount = static_cast(qIndices.size()); - swapChainCI.pQueueFamilyIndices = qIndices.data(); + swapChainCI.imageSharingMode = vk::SharingMode::eConcurrent, + qIndices = { qFamilyIndices.graphicsFamily.value(), qFamilyIndices.presentFamily.value() }; + swapChainCI.setQueueFamilyIndices(qIndices); } else { - swapChainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapChainCI.imageSharingMode = vk::SharingMode::eExclusive; } - swapChainCI.preTransform = scDetails.capabilities.currentTransform; - swapChainCI.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapChainCI.presentMode = selectSwapChainPresentMode(scDetails.presentModes); - swapChainCI.clipped = VK_TRUE; - swapChainCI.oldSwapchain = VK_NULL_HANDLE; - VkResult result = vkCreateSwapchainKHR(device, &swapChainCI, nullptr, &swapChain); - if (result != VK_SUCCESS) { - vLog.error("createSwapChain: Couldn not create swap chain", "VkResult:", STR_VK_RESULT(result)); - throw std::runtime_error("createSwapChain: Couldn not create swap chain"); + vk::Result result = device.createSwapchainKHR(&swapChainCI, nullptr, &swapChain); + if (result != vk::Result::eSuccess) { + vLog.error("createSwapChain: Couldn not create swap chain", "VkResult:", result); + throw getVkException(result, "Couldn not create swap chain", "VulkanInstance::createSwapChain"); } // get image handles - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); - scImages.resize(imageCount); - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, scImages.data()); + std::tie(result, scImages) = device.getSwapchainImagesKHR(swapChain); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Couldn not get swap chain images", "VulkanInstance::createSwapChain"); + } vLog.log0("createSwapChain: Created swap chain."); } @@ -1640,7 +1536,10 @@ using std::uint32_t; glfwWaitEvents(); } vLog.log0("recreateSwapChain: new framebuffer size:", width, height); - vkDeviceWaitIdle(device); + vk::Result result = device.waitIdle(); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to wait for device idle", "VulkanInstance::recreateSwapChain"); + } cleanupSwapChain(); createSwapChain(); @@ -1649,6 +1548,7 @@ using std::uint32_t; createCommandBuffers(commandBuffersBegin); createCommandBuffers(commandBuffersEnd); + // TODO: order? for (auto& f : scRecreateCallbacks) { f(); } @@ -1661,31 +1561,29 @@ using std::uint32_t; void VulkanInstance::cleanupSwapChain() { for (auto& imageView : scImageViews) { - vkDestroyImageView(device, imageView, nullptr); + device.destroyImageView(imageView, nullptr); } - vkDestroySwapchainKHR(device, swapChain, nullptr); + device.destroySwapchainKHR(swapChain, nullptr); } void VulkanInstance::createSwapChainImageViews() { scImageViews.resize(scImages.size()); for (unsigned int i = 0; i < scImageViews.size(); i++) { - createImageView(scImageFormat, scImages[i], scImageViews[i], VK_IMAGE_ASPECT_COLOR_BIT); + createImageView(scImageFormat, scImages[i], scImageViews[i], vk::ImageAspectFlagBits::eColor); } vLog.log0("createImageViews: Created", scImageViews.size(), "image views."); } - uint32_t VulkanInstance::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) { - VkPhysicalDeviceMemoryProperties memoryProperties{}; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties); - for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) { + uint32_t VulkanInstance::findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties) { + for (uint32_t i = 0; i < phDevMemProperties.memoryProperties.memoryTypeCount; i++) { // if ith bit of typefilter is set - if ((typeFilter & (1 << i)) and (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { + if ((typeFilter & (1 << i)) and (phDevMemProperties.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { return i; } } - throw VkException("Could not find suitable memory type", "findMemoryType"); + throw VkException("Could not find suitable memory type", "VulkanInstance::findMemoryType"); } @@ -1697,29 +1595,29 @@ using std::uint32_t; // COMMAND POOLS void VulkanInstance::createCommandPools() { - /* QueueFamilyIndicjes queueFamilyIndices = findQueueFamilies(physicalDevice); */ - VkCommandPoolCreateInfo commandPoolGraphicsCI{}; - commandPoolGraphicsCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - commandPoolGraphicsCI.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - commandPoolGraphicsCI.queueFamilyIndex = qFamilyIndices.graphicsFamily.value(); - VkResult result = vkCreateCommandPool(device, &commandPoolGraphicsCI, nullptr, &commandPoolGraphics); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create graphics command pool", "createCommandPool"); - } + /* QueueFamilyIndicjes queueFamilyIndices = findQueueFamilies(physicalDevice); */ + vk::CommandPoolCreateInfo commandPoolGraphicsCI { + .flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer, + .queueFamilyIndex = qFamilyIndices.graphicsFamily.value(), + }; + vk::Result result = device.createCommandPool(&commandPoolGraphicsCI, nullptr, &commandPoolGraphics); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create graphics command pool", "createCommandPool"); + } - if (qFamilyIndices.transferFamily.has_value()) { - VkCommandPoolCreateInfo commandPoolTransferCI{}; - commandPoolTransferCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - commandPoolTransferCI.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - commandPoolTransferCI.queueFamilyIndex = qFamilyIndices.transferFamily.value(); - result = vkCreateCommandPool(device, &commandPoolTransferCI, nullptr, &commandPoolTransfer); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to create transfer command pool", "createCommandPool"); - } - } - else { - commandPoolTransfer = commandPoolGraphics; - } + if (qFamilyIndices.transferFamily.has_value()) { + vk::CommandPoolCreateInfo commandPoolTransferCI { + .flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer, + .queueFamilyIndex = qFamilyIndices.transferFamily.value(), + }; + result = device.createCommandPool(&commandPoolTransferCI, nullptr, &commandPoolTransfer); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create transfer command pool", "createCommandPool"); + } + } + else { + commandPoolTransfer = commandPoolGraphics; + } } @@ -1729,45 +1627,29 @@ using std::uint32_t; renderFinishedSemaphores.resize(getMaxFramesInFlight()); inFlightFences.resize(getMaxFramesInFlight()); - VkSemaphoreCreateInfo semaphoreCI{}; - semaphoreCI.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + vk::SemaphoreCreateInfo semaphoreCI; - VkFenceCreateInfo fenceCI{}; - fenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceCI.flags = VK_FENCE_CREATE_SIGNALED_BIT; + vk::FenceCreateInfo fenceCI { + .flags = vk::FenceCreateFlagBits::eSignaled, + }; for (size_t i = 0; i < getMaxFramesInFlight(); i++) { - VkResult result = vkCreateSemaphore(device, &semaphoreCI, nullptr, &imageAvailableSemaphores[i]); - if (result != VK_SUCCESS) { + vk::Result result = device.createSemaphore(&semaphoreCI, nullptr, &imageAvailableSemaphores[i]); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to create imageAvailableSemaphores", "createSyncObjects"); } - result = vkCreateSemaphore(device, &semaphoreCI, nullptr, &renderFinishedSemaphores[i]); - if (result != VK_SUCCESS) { + result = device.createSemaphore(&semaphoreCI, nullptr, &renderFinishedSemaphores[i]); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to create renderFinishedSemaphores", "createSyncObjects"); } - result = vkCreateFence(device, &fenceCI, nullptr, &inFlightFences[i]); - if (result != VK_SUCCESS) { + result = device.createFence(&fenceCI, nullptr, &inFlightFences[i]); + if (result != vk::Result::eSuccess) { throw getVkException(result, "Failed to create inFlightFences", "createSyncObjects"); } } } - /* void VulkanInstance::createDepthImageAndView() { */ - /* VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; */ - /* VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; */ - /* VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL; */ - /* VkFormat depthFormat = findDepthFormat(); */ - - /* createImage(scExtent.width, scExtent.height, depthFormat, tiling, imageUsage, memoryProperties, depthImage, depthImageMemory); */ - /* createImageView(depthFormat, depthImage, depthImageView, VK_IMAGE_ASPECT_DEPTH_BIT); */ - - /* transitionImageLayout(depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); */ - - - /* } */ - - // SHADERS std::vector VulkanInstance::readFile(const std::string& filename) { std::ifstream file(filename, std::ios::ate | std::ios::binary); @@ -1792,11 +1674,12 @@ using std::uint32_t; // DEBUG void VulkanInstance::setupDebugMessenger() { // get the address of the vkCreateDebugUtilsMessengerEXT function - VkResult result = runVkResultFunction("vkCreateDebugUtilsMessengerEXT", instance, &debugUtilsMessengerCI, nullptr, &debugMessenger); - if (result != VK_SUCCESS) { - throw getVkException(result, "Failed to initialise debug messenger", "setupDebugMessenger"); + VkDebugUtilsMessengerCreateInfoEXT debugCI = static_cast(debugUtilsMessengerCI); + vk::Result result = runVkResultFunction("vkCreateDebugUtilsMessengerEXT", instance, &debugCI, nullptr, &debugMessenger); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to initialise debug messenger", "VulkanInstance::setupDebugMessenger"); } - /* auto f = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT")); */ + /* auto f = reinterpret_cast(vk::getInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT")); */ /* if (f == nullptr) { throw std::runtime_error("Failed to initialise debug messenger."); } */ /* else { */ /* f(instance, &debugUtilsMessengerCreateInfo, nullptr, &debugMessenger); */ @@ -1865,5 +1748,5 @@ using std::uint32_t; -} // namespace gz::vk +} // namespace gz::vlk diff --git a/src/vulkan_instance.hpp b/src/vulkan_instance.hpp index 4533fcf..9a2fade 100644 --- a/src/vulkan_instance.hpp +++ b/src/vulkan_instance.hpp @@ -1,57 +1,45 @@ #pragma once #define GLM_FORCE_DEPTH_ZERO_TO_ONE -#include +/* #include */ #define GLFW_INCLUDE_VULKAN #include +#define VULKAN_HPP_NO_EXCEPTIONS +#define VULKAN_HPP_NO_CONSTRUCTORS +#include + #include "vk_convert.hpp" #include "vertex.hpp" -#include "shape.hpp" #include "vulkan_util.hpp" #include "vulkan_allocator.hpp" +#include "vulkan_settings.hpp" #include #include #include -#include - #include #include -namespace gz::vk { - constexpr bool throwExceptionOnValidationError = true; - constexpr gz::Color VULKAN_MESSAGE_PREFIX_COLOR = gz::Color::BO_BLUE; - constexpr gz::Color VULKAN_MESSAGE_TIME_COLOR = gz::Color::BLUE; - const std::string CONFIG_FILE = "vulkan.conf"; -#define SettingsTypes uint32_t, bool, float - - /* const std::string MODEL_PATH = "models/gazebo-3d-model/gazebo.obj"; */ - /* const std::string TEXTURE_PATH = "models/gazebo-3d-model/gazebo_diffuse.png"; */ - - const std::string MODEL_PATH = "models/armoire-3d-model/Armoire.obj"; - const std::string TEXTURE_PATH = "models/armoire-3d-model/Armoire_diffuse.png"; - - const gz::util::unordered_string_map INITIAL_SETTINGS = { - { "framerate", "60" }, - { "anisotropy_enable", "false" }, - { "max_anisotropy", "1" }, - { "max_frames_in_flight", "3" }, - /* { "", "" } */ - }; - - - constexpr VkClearColorValue missingTextureColor = { { 0.4f, 0.0f, 0.4f, 1.0f } }; - const int BINDING = 0; - const uint32_t NO_FLAGS = 0; +namespace gz::vlk { + constexpr vk::MemoryMapFlags NO_MEM_FLAGS; + constexpr vk::AccessFlags NO_ACC_FLAGS; + constexpr vk::AccessFlags2 NO_ACC_2_FLAGS; + constexpr vk::CommandBufferResetFlags NO_CMD_RESET_FLAGS; const uint32_t NO_OFFSET = 0; - constexpr VkAllocationCallbacks* NO_ALLOC = nullptr; - const size_t VERTEX_BUFFER_SIZE = 512; - const size_t INDEX_BUFFER_SIZE = 512; + constexpr vk::AllocationCallbacks* NO_ALLOC = nullptr; + /* const vk::ImageSubresourceRange DEFAULT_SUBRESOURCE_RANGE { */ + /* .aspectMask = vk::ImageAspectFlagBits::eColor, */ + /* .baseMipLevel = 0, */ + /* .levelCount = 1, */ + /* .baseArrayLayer = 0, */ + /* .layerCount = 1, */ + /* }; */ + enum InstanceCommandPool { POOL_GRAPHICS, POOL_TRANSFER }; @@ -67,7 +55,7 @@ namespace gz::vk { * These functions will probably called from your `main` function and loop. */ /// @{ - VulkanInstance(gz::SettingsManagerCreateInfosmCI) : settings(smCI), allocator(*this) {}; + VulkanInstance(gz::SettingsManagerCreateInfosmCI) : settings(smCI), allocator(*this) {}; /** * @brief Initializes the vulkan instance * @details @@ -158,12 +146,13 @@ namespace gz::vk { */ public: /// @{ - const VkDevice& getDevice() const { return device; } - const VkExtent2D& getScExtent() const { return scExtent; } - const std::vector& getScImages() const { return scImages; } - const VkFormat& getScImageFormat() const { return scImageFormat; } + const vk::Device& getDevice() const { return device; } + const vk::Extent2D& getScExtent() const { return scExtent; } + const std::vector& getScImages() const { return scImages; } + const vk::Format& getScImageFormat() const { return scImageFormat; } + const vk::Format& getDepthFormat() const { return depthFormat; } - SettingsManager& getSettings() { return settings; } + SettingsManager& getSettings() { return settings; } /** * @brief Get the maximum number of frames in flight @@ -176,28 +165,30 @@ namespace gz::vk { */ uint32_t getCurrentFrame() const { return currentFrame; } - void submitThisFrame(VkCommandBuffer& cmdBuffer); + void submitThisFrame(vk::CommandBuffer& cmdBuffer); /** * @brief Copy from srcBuffer to dstBuffer * @details * Uses @ref beginSingleTimeCommands() "a single time command buffer" from commandPoolTransfer. */ - void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); + void copyBuffer(vk::Buffer srcBuffer, vk::Buffer dstBuffer, vk::DeviceSize size); /** * @brief Begin a command buffer that is going to be used once * @param commandPool: The command pool from which the buffer should be allocated */ - VkCommandBuffer beginSingleTimeCommands(InstanceCommandPool commandPool); + vk::CommandBuffer beginSingleTimeCommands(InstanceCommandPool commandPool); /** * @brief Submit cmdBuffer on the queue and free it afterwards * @param cmdBuffer: Command buffer returned by beginSingleTimeCommands() * @param commandPool: The same pool as passed to beginSingleTimeCommands() + * @details + * After command buffer is submitted on the specified queue, the function waits for the queue to idle */ - void endSingleTimeCommands(VkCommandBuffer cmdBuffer, InstanceCommandPool commandPool); + void endSingleTimeCommands(vk::CommandBuffer cmdBuffer, InstanceCommandPool commandPool); - void loadModel(VerticesAndIndices& model); + void loadModel(const std::string& path, VerticesAndIndices& model); /// @} /** @@ -212,16 +203,16 @@ namespace gz::vk { /** * @brief Create MAX_FRAMES_IN_FLIGHT command buffers from the commandPoolGraphics */ - void createCommandBuffers(std::vector& commandBuffers); + void createCommandBuffers(std::vector& commandBuffers); /** * @brief Destroy all command buffers (must be from commandPoolGraphics) */ - void destroyCommandBuffers(std::vector& commandBuffers); + void destroyCommandBuffers(std::vector& commandBuffers); /** * @brief Create a descriptor layout with bindings */ - void createDescriptorSetLayout(std::vector bindings, VkDescriptorSetLayout& layout); + void createDescriptorSetLayout(std::vector bindings, vk::DescriptorSetLayout& layout); /** * @brief Create a new graphics pipeline @@ -236,17 +227,19 @@ namespace gz::vk { * @details * Create a pipeline with: * - 2 shader stages: vertex and fragment shader - * - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, vertices are triangles + * - vk::PrimitiveTopology::eTriangleList, vertices are triangles * - viewport viewing the whole image as described by scExtent * - scissor with offset (0, 0) * - rasterizer: * - triangles are filled with the colors from the vertex (VK_POLYGON_FILL) - * - counter clockwise front face (VK_FRONT_FACE_COUNTER_CLOCKWISE) + * - counter clockwise front face (vk::FrontFace::eCounterClockwise) + * + * @todo Move shader module creation and maybe pipelineshaderstagecreateinfo outside */ template - void createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector& descriptorSetLayouts, bool useDepthStencil, VkRenderPass& renderPass, Pipeline& pipeline); + void createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector& descriptorSetLayouts, bool useDepthStencil, vk::RenderPass& renderPass, Pipeline& pipeline, vk::SpecializationInfo* fragSI=nullptr, vk::SpecializationInfo* vertSI=nullptr); - VkShaderModule createShaderModule(const std::vector& code); + vk::ShaderModule createShaderModule(const std::vector& code); /** * @brief Allocate memory, create a buffer and bind buffer to memory @@ -254,15 +247,16 @@ namespace gz::vk { * @param buffer The (null) handle to the buffer * @param bufferMemory Reference to an (uninitialized) MemoryInfo struct. It will be valid when the function returns * @param properties Properties that the buffers memory needs to satisfy + * @param qFamiliesWithAccess [Optional] vector of queue families that have access to the buffer. Only needed with SHARING_MODE_CONCURRENT * @details * The memory the buffer will be bound to is HOST_VISIBLE and HOST_COHERENT * */ - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, MemoryInfo& bufferMemory, VkSharingMode sharingMode=VK_SHARING_MODE_EXCLUSIVE, std::vector* qFamiliesWithAccess=nullptr); + void createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties, vk::Buffer& buffer, MemoryInfo& bufferMemory, vk::SharingMode sharingMode=vk::SharingMode::eExclusive, std::vector* qFamiliesWithAccess=nullptr); /** * @brief Destroy buffer and free memory */ - void destroyBuffer(VkBuffer& buffer, MemoryInfo& bufferMemory); + void destroyBuffer(vk::Buffer& buffer, MemoryInfo& bufferMemory); /** * @brief Create a vertex buffer @@ -273,7 +267,7 @@ namespace gz::vk { * The function is instantiated for Vertex2D and Vertex3D */ template - void createVertexBuffer(size_t vertexCount, VkBuffer& vertexBuffer, MemoryInfo& vertexBufferMemory, VkDeviceSize& vertexBufferSize); + void createVertexBuffer(size_t vertexCount, vk::Buffer& vertexBuffer, MemoryInfo& vertexBufferMemory, vk::DeviceSize& vertexBufferSize); /** * @brief Create an index buffer @@ -284,30 +278,30 @@ namespace gz::vk { * The function is instantiated for uint16_t and uint32_t */ template - void createIndexBuffer(size_t indexCount, VkBuffer& indexBuffer, MemoryInfo& indexBufferMemory, VkDeviceSize& indexBufferSize); + void createIndexBuffer(size_t indexCount, vk::Buffer& indexBuffer, MemoryInfo& indexBufferMemory, vk::DeviceSize& indexBufferSize); /** * @brief Create MAX_FRAMES_IN_FLIGHT uniform buffers */ template - void createUniformBuffers(std::vector& uniformBuffers, std::vector& uniformBuffersMemory); + void createUniformBuffers(std::vector& uniformBuffers, std::vector& uniformBuffersMemory); /** * @brief Create as many framebuffers as the swap chain has images, with the extent of the swap chain */ - void createFramebuffers(std::vector& framebuffers, std::vector& imageViews, VkRenderPass& renderPass); + void createFramebuffers(std::vector& framebuffers, std::vector& imageViews, vk::RenderPass& renderPass, vk::ImageView depthImageView=VK_NULL_HANDLE); /** * @brief Destroy the framebuffers */ - void destroyFramebuffers(std::vector& framebuffers); + void destroyFramebuffers(std::vector& framebuffers); /** * @brief Create a texture sampler * @todo add options and documentation */ - void createTextureSampler(VkSampler& sampler); + void createTextureSampler(vk::Sampler& sampler); - void destroyTextureSampler(VkSampler& sampler); + void destroyTextureSampler(vk::Sampler& sampler); /** * @name Public Interface: Image utility @@ -319,15 +313,15 @@ namespace gz::vk { /** * @brief Create a 2D image, allocate the imageMemory and bind the image to it */ - void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkImage& image, MemoryInfo& imageMI); - void destroyImage(VkImage& image, MemoryInfo& imageMemory); + void createImage(uint32_t width, uint32_t height, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags memoryProperties, vk::Image& image, MemoryInfo& imageMI); + void destroyImage(vk::Image& image, MemoryInfo& imageMemory); /** * @brief Create a 2D imageView with format for image. */ - void createImageView(VkFormat format, VkImage& image, VkImageView& imageView, VkImageAspectFlags aspectFlags); - void destroyImageView(VkImageView& imageView); + void createImageView(vk::Format format, vk::Image& image, vk::ImageView& imageView, vk::ImageAspectFlags aspectFlags); + void destroyImageView(vk::ImageView& imageView); - void copyBufferToImage(VkBuffer buffer, VkImage image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height); + void copyBufferToImage(vk::Buffer buffer, vk::Image image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height); /** * @todo make a version using vkCmdResolveImage for multisampled images * @brief Copy srcImage to dstImage @@ -342,7 +336,7 @@ namespace gz::vk { * @param srcImage Image with layout TRANSFER_SRC_OPTIMAL * @param dstImage Image with layout TRANSFER_DST_OPTIMAL */ - void copyImageToImage(VkCommandBuffer& cmdBuffer, VkImage srcImage, VkImage dstImage, VkExtent2D extent); //, VkCommandPool& commandPool=commandPoolTransfer); + void copyImageToImage(vk::CommandBuffer& cmdBuffer, vk::Image srcImage, vk::Image dstImage, vk::Extent2D extent); //, vk::CommandPool& commandPool=commandPoolTransfer); /** * @brief Transition the layout of image from oldLayout to newLayout * @details @@ -356,12 +350,12 @@ namespace gz::vk { * If you do not provide a command buffer, a command buffer from the indicated queue will be created and submitted. * If you do provide a command buffer, the command is recorded but NOT submitted. * - * The transition is done by submitting a VkImageMemoryBarrier2 + * The transition is done by submitting a vk::ImageMemoryBarrier2 * * @param cmdBuffer [Optional] The command buffer where the command will be recorded to - * @throws VkUserError if the transition is not supported. + * @throws vk::UserError if the transition is not supported. */ - void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandBuffer* cmdBuffer=nullptr); + void transitionImageLayout(vk::Image image, vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::CommandBuffer* cmdBuffer=nullptr); /// @} @@ -393,7 +387,7 @@ namespace gz::vk { * @name Settings */ /// @{ - gz::SettingsManager settings; + gz::SettingsManager settings; /** * @brief Set valid values for the SettingsManager according to phDevFeatures and phDevProperties * @details @@ -457,37 +451,48 @@ namespace gz::vk { * @name Instance */ /// @{ - VkInstance instance; + vk::Instance instance; /** * @brief Create the vulkan instance * @details * -# check if validationLayers are available (if enabled) * -# create instance with info * -# check if all extensions required by glfw are available + * @throws VkException if: + * - validation layers are enabled but not supported + * - instance creation fails + * - not all required instance extensions are available */ void createInstance(); + /** + * @brief Get all the required instance extensions + * @details + * The required extensions are: + * - all extensions required by glfw (glfwGetRequiredInstanceExtensions()) + * - if validation layers are enabled: "VK_EXT_debug_utils" + */ + std::vector getRequiredInstanceExtensions() const; + /** + * @brief Check if @ref settings::validationLayers "all requrested validation layers" are supported + */ + bool validationLayersSupported(); /// @} /** - * @name Physical device + * @name Physical device (selection process) + * @brief Member variables and functions that are used to select a physical device */ /// @{ - VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - /// all the properties of the selected physcial device - VkPhysicalDeviceProperties phDevProperties; - /// all the features that the selected physical device supports - PhysicalDeviceFeatures phDevFeatures; - /** - * @brief Get the required physical device features - * @details - * The required features are: - * - synchronization2 - */ - PhysicalDeviceFeatures getRequiredFeatures() const; /** * @brief Assign the physicalDevice handle to the @ref rateDevice "best rated" GPU * @details - * After this method, physicalDevice, phDevProperties and phDevFeatures will be initialized + * After this method, the following members will be initalized: + * - physicalDevice + * - phDevProperties + * - phDevFeatures + * - phDevMemProperties + * - qFamilyIndices + * - depthFormat */ void selectPhysicalDevice(); /** @@ -499,20 +504,44 @@ namespace gz::vk { * - support all necessary extensions * - have swap chain support */ - unsigned int rateDevice(VkPhysicalDevice device); + unsigned int rateDevice(vk::PhysicalDevice device); + /** + * @brief Get the required physical device features + * @details + * The required features are: + * - synchronization2 + */ + PhysicalDeviceFeatures getRequiredDeviceFeatures() const; + + /** + * @name Physical device (selected) + * @brief Member variables and functions that are usable/initalized after selectPhysicalDevice + */ + /// @{ + vk::PhysicalDevice physicalDevice = VK_NULL_HANDLE; + /// all the properties of the selected physcial device + vk::PhysicalDeviceProperties2 phDevProperties; + /// memory properties of the selected physical device + vk::PhysicalDeviceMemoryProperties2 phDevMemProperties; + /// all the features that the selected physical device supports + PhysicalDeviceFeatures phDevFeatures; + /// preferred depth format + vk::Format depthFormat; + /** * @brief Find the best of the supported formats * @param candidates Candidate format, from best to worst * @returns The first format from candidates that is supported + * @throws VkException if no suitable format is found */ - VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features); + vk::Format findSupportedFormat(const std::vector& candidates, vk::ImageTiling tiling, vk::FormatFeatureFlags features); /// @} /** * @name Memory management */ /// @{ - uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); + uint32_t findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties); VulkanAllocator allocator; /// @} @@ -520,19 +549,19 @@ namespace gz::vk { * @name Queue */ /// @{ - QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); + QueueFamilyIndices findQueueFamilies(vk::PhysicalDevice device); QueueFamilyIndices qFamilyIndices; - VkQueue graphicsQ; - VkQueue presentQ; + vk::Queue graphicsQ; + vk::Queue presentQ; // if possible, use dedicated transferQ. if not available, transferQ = graphicsQ - VkQueue transferQ; + vk::Queue transferQ; /// @} /** * @name Logical device */ /// @{ - VkDevice device; + vk::Device device; /** * @details * request anisotropic sampling feature @@ -544,7 +573,7 @@ namespace gz::vk { * @name Surface */ /// @{ - VkSurfaceKHR surface; + vk::SurfaceKHR surface; void createSurface(); /// @} @@ -552,22 +581,23 @@ namespace gz::vk { * @name Swap chain */ /// @{ - VkSwapchainKHR swapChain; - std::vector scImages; - std::vector scImageViews; - VkFormat scImageFormat; - VkExtent2D scExtent; + vk::SwapchainKHR swapChain; + std::vector scImages; + std::vector scImageViews; + vk::Format scImageFormat; + vk::Extent2D scExtent; - SwapChainSupport querySwapChainSupport(VkPhysicalDevice device); + SwapChainSupport querySwapChainSupport(vk::PhysicalDevice device); /** * @todo Rate formats if preferred is not available + * @todo Move back to SurfaceFormatKHR? 2 is an (for now) unnecessary extension */ - VkSurfaceFormatKHR selectSwapChainSurfaceFormat(const std::vector& availableFormats); + vk::SurfaceFormat2KHR selectSwapChainSurfaceFormat(const std::vector& availableFormats); /** * @todo Check settings for preferred mode */ - VkPresentModeKHR selectSwapChainPresentMode(const std::vector& availableModes); - VkExtent2D selectSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); + vk::PresentModeKHR selectSwapChainPresentMode(const std::vector& availableModes); + vk::Extent2D selectSwapExtent(const vk::SurfaceCapabilities2KHR& capabilities); void createSwapChain(); void createSwapChainImageViews(); void cleanupSwapChain(); @@ -589,31 +619,31 @@ namespace gz::vk { * @name Command pools */ /// @{ - VkCommandPool commandPoolGraphics; - VkCommandPool commandPoolTransfer; + vk::CommandPool commandPoolGraphics; + vk::CommandPool commandPoolTransfer; void createCommandPools(); /// @} /** * @name Command buffers */ /// @{ - std::vector commandBuffersBegin; - std::vector commandBuffersEnd; + std::vector commandBuffersBegin; + std::vector commandBuffersEnd; /** * @brief All command buffers to submit on graphics queue for the current frame * @details * Use submitThisFrame() to submit a command buffer */ - std::vector commandBuffersToSubmitThisFrame; + std::vector commandBuffersToSubmitThisFrame; /// @} /** * @name Synchronization */ /// @{ - std::vector imageAvailableSemaphores; - std::vector renderFinishedSemaphores; - std::vector inFlightFences; + std::vector imageAvailableSemaphores; + std::vector renderFinishedSemaphores; + std::vector inFlightFences; void createSyncObjects(); /// @} @@ -634,7 +664,7 @@ namespace gz::vk { */ /// @{ template - VkResult runVkResultFunction(const char* name, Args&&... args); + vk::Result runVkResultFunction(const char* name, Args&&... args); template void runVkVoidFunction(const char* name, Args&&... args); @@ -676,14 +706,14 @@ namespace gz::vk { // UNIFORM BUFFERS // template - void VulkanInstance::createUniformBuffers(std::vector& uniformBuffers, std::vector& uniformBuffersMemory) { - VkDeviceSize bufferSize = sizeof(T); + void VulkanInstance::createUniformBuffers(std::vector& uniformBuffers, std::vector& uniformBuffersMemory) { + vk::DeviceSize bufferSize = sizeof(T); uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT); uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT); for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]); + createBuffer(bufferSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, uniformBuffers[i], uniformBuffersMemory[i]); } } @@ -691,14 +721,14 @@ namespace gz::vk { // UTILITY // template - VkResult VulkanInstance::runVkResultFunction(const char* name, Args&&... args) { + vk::Result VulkanInstance::runVkResultFunction(const char* name, Args&&... args) { auto f = reinterpret_cast(vkGetInstanceProcAddr(instance, name)); if (f == nullptr) { vLog.error("getVkFunction: Could not get function:", name); throw std::runtime_error("getVkFunction: Could not get function."); } else { - return f(std::forward(args)...); + return vk::Result(f(std::forward(args)...)); } }; diff --git a/src/vulkan_settings.hpp b/src/vulkan_settings.hpp new file mode 100644 index 0000000..3deea63 --- /dev/null +++ b/src/vulkan_settings.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include + +#define VULKAN_HPP_NO_EXCEPTIONS +#define VULKAN_HPP_NO_CONSTRUCTORS +#include + +namespace gz::vlk::settings { + constexpr bool throwExceptionOnValidationError = true; + constexpr gz::Color VULKAN_MESSAGE_PREFIX_COLOR = gz::Color::BO_BLUE; + constexpr gz::Color VULKAN_MESSAGE_TIME_COLOR = gz::Color::BLUE; + const std::string CONFIG_FILE = "vulkan.conf"; + + /* const std::string MODEL_PATH = "models/gazebo-3d-model/gazebo.obj"; */ + /* const std::string TEXTURE_PATH = "models/gazebo-3d-model/gazebo_diffuse.png"; */ + + const std::string MODEL_PATH = "models/armoire-3d-model/Armoire.obj"; + const std::string TEXTURE_PATH = "models/armoire-3d-model/Armoire_diffuse.png"; + +#define VULKAN_SETTINGS_MAN_TYPES uint32_t, bool, float + const gz::util::unordered_string_map INITIAL_SETTINGS = { + { "framerate", "60" }, + { "anisotropy_enable", "false" }, + { "max_anisotropy", "1" }, + { "max_frames_in_flight", "3" }, + /* { "", "" } */ + }; + constexpr vk::ClearColorValue missingTextureColor = { std::array{ 0.4f, 0.0f, 0.4f, 1.0f } }; + + constexpr size_t VERTEX_BUFFER_SIZE = 512; + constexpr size_t INDEX_BUFFER_SIZE = 512; + + + constexpr std::array deviceExtensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + /* VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME */ + }; + + // DEBUG + /** + * @brief Which message severities to log in VulkanInstance::debugLog() + */ + constexpr vk::DebugUtilsMessageSeverityFlagsEXT debugMessageSevereties = + vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose | + vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo | + vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | + vk::DebugUtilsMessageSeverityFlagBitsEXT::eError; + + /** + * @brief Which message types to log in VulkanInstance::debugLog() + */ + constexpr vk::DebugUtilsMessageTypeFlagsEXT debugMessageTypes = + vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | + vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation | + vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance; + + // VALIDATION LAYERS + constexpr std::array validationLayers { + "VK_LAYER_KHRONOS_validation", + }; + constexpr std::array validationFeaturesEnable { + vk::ValidationFeatureEnableEXT::eDebugPrintf, + vk::ValidationFeatureEnableEXT::eSynchronizationValidation, + vk::ValidationFeatureEnableEXT::eBestPractices + }; + constexpr vk::ValidationFeaturesEXT validationFeatures { + .enabledValidationFeatureCount = static_cast(validationFeaturesEnable.size()), + .pEnabledValidationFeatures = validationFeaturesEnable.data(), + }; +} // namespace gz::vlk::setting