diff --git a/src/renderer/renderer.hpp b/src/renderer/renderer.hpp index 1a6a3f6..930415c 100644 --- a/src/renderer/renderer.hpp +++ b/src/renderer/renderer.hpp @@ -36,6 +36,20 @@ namespace gz::vlk { void cleanup_(); VulkanInstance& vk; TextureManager& textureManager; + /** + * @name Image (render targets) + * @details + * The images are used as render targets, `#ifdef GZ_RENDERER_OWN_RENDER_IMAGES` + * + * After rendering, the current image gets blitted onto the current swap chain image. + * @todo + */ + /// @{ + std::vector renderImages; + std::vector renderImageMemory; + std::vector renderImageViews; + vk::Sampler imageSampler; + /// @} std::vector commandBuffers; /// On device local memory diff --git a/src/renderer/renderer2D.cpp b/src/renderer/renderer2D.cpp index b1e4e52..9095ce5 100644 --- a/src/renderer/renderer2D.cpp +++ b/src/renderer/renderer2D.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace gz::vlk { @@ -35,9 +36,9 @@ namespace gz::vlk { vk.createVertexBuffer(vertexCount, vertexBuffer, vertexBufferMemory, vertexBufferSize); vk.createIndexBuffer(indexCount, indexBuffer, indexBufferMemory, indexBufferSize); initSwapChainDependantResources(); - VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan("Renderer2D", - { &pipelines[PL_2D].pipeline, &renderPass, &vertexBuffer, &vertexBufferMemory, &indexBuffer, &indexBufferMemory }, - { &framebuffers, &images, &imageMemory, &imageViews, &commandBuffers })); + VulkanInstance::registerObjectUsingVulkan("Renderer2D", + &pipelines[R2Render].pipeline, &renderPass, &vertexBuffer, &vertexBufferMemory.memory, &indexBuffer, &indexBufferMemory.memory, + &framebuffers, &renderImages, &renderImageViews, &commandBuffers); // &renderImageMemory, rLog("Created Renderer2D"); } @@ -57,8 +58,8 @@ namespace gz::vlk { // void Renderer2D::initSwapChainDependantResources() { createRenderPass(); - createImages(); - vk.createFramebuffers(framebuffers, imageViews, renderPass); + createImageResources(); + vk.createFramebuffers(framebuffers, renderImageViews, renderPass); std::vector descriptorSetLayouts = { textureManager.getDescriptorSetLayout() }; // specialization constant for sampler2D array length = atlas count @@ -71,23 +72,55 @@ namespace gz::vlk { vk::SpecializationInfo specI; specI.setData(atlasCount); specI.setMapEntries(specME); - vk.createGraphicsPipeline("shaders/vert2D.spv", "shaders/frag2D.spv", descriptorSetLayouts, false, renderPass, pipelines[PL_2D], &specI); + + // VERTEX 2D PIPELINE + auto vertShaderCode = readBinaryFile("shaders/shader2D.vert.spv"); + auto fragShaderCode = readBinaryFile("shaders/shader2D.frag.spv"); + + vk::ShaderModule vertShaderModule = vk.createShaderModule(vertShaderCode); + vk::ShaderModule fragShaderModule = vk.createShaderModule(fragShaderCode); + + std::vector shaderStages; + + shaderStages.emplace_back(vk::PipelineShaderStageCreateInfo { + .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertShaderModule, + .pName = "main", + .pSpecializationInfo = nullptr, + }); + shaderStages.emplace_back(vk::PipelineShaderStageCreateInfo { + .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragShaderModule, + .pName = "main", + .pSpecializationInfo = nullptr, + }); + + vk::GraphicsPipelineCreateInfo pipelineCI { + .renderPass = renderPass, + .subpass = 0, + }; + pipelineCI.setStages(shaderStages); + + vk.createGraphicsPipeline(std::move(pipelineCI), &descriptorSetLayouts, true, pipelines[R2Render]); + + vk.getDevice().destroyShaderModule(vertShaderModule, nullptr); + vk.getDevice().destroyShaderModule(fragShaderModule, nullptr); } void Renderer2D::cleanupSwapChainDependantResources() { // destroy pipelines - pipelines.destroy(vk.getDevice()); + pipelines.clear(vk.getDevice()); vk.destroyFramebuffers(framebuffers); - for (size_t i = 0; i < images.size(); i++) { - vk.destroyImageView(imageViews[i]); - vk.destroyImage(images[i], imageMemory[i]); +#ifndef RENDERER_2D_RENDER_TO_SWAP_CHAIN + for (size_t i = 0; i < renderImages.size(); i++) { + vk.destroyImageView(renderImageViews[i]); + vk.destroyImage(renderImages[i], renderImageMemory[i]); } +#endif vk.getDevice().destroyRenderPass(renderPass, nullptr); - - } @@ -100,15 +133,24 @@ namespace gz::vlk { // // IMAGES // - void Renderer2D::createImages() { - images.resize(vk.getScImages().size()); - imageMemory.resize(vk.getScImages().size()); - imageViews.resize(vk.getScImages().size()); + void Renderer2D::createImageResources() { + renderImageViews.resize(vk.getScImages().size()); +#ifndef RENDERER_2D_RENDER_TO_SWAP_CHAIN + renderImages.resize(vk.getScImages().size()); + renderImageMemory.resize(vk.getScImages().size()); 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::ImageTiling::eOptimal, usage, vk::MemoryPropertyFlagBits::eDeviceLocal, images[i], imageMemory[i]); - vk.createImageView(vk.getScImageFormat(), images[i], imageViews[i], vk::ImageAspectFlagBits::eColor); + for (size_t i = 0; i < renderImages.size(); i++) { + vk.createImage(vk.getScExtent().width, vk.getScExtent().height, vk.getScImageFormat(), vk::ImageTiling::eOptimal, usage, vk::MemoryPropertyFlagBits::eDeviceLocal, renderImages[i], renderImageMemory[i]); + vk.createImageView(vk.getScImageFormat(), renderImages[i], renderImageViews[i], vk::ImageAspectFlagBits::eColor); } + vk.createTextureSampler(imageSampler); + rLog.log0("createImageResources: created images, views and sampler"); +#else + for (size_t i = 0; i < renderImages.size(); i++) { + vk.createImageView(vk.getScImageFormat(), vk.getScImages()[i], renderImageViews[i], vk::ImageAspectFlagBits::eColor); + } + rLog.log0("createImageResources: created image views"); +#endif } // @@ -145,14 +187,15 @@ namespace gz::vlk { /* depthAttachmentRef.attachment = 1; */ /* depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; */ - vk::SubpassDescription2 subpass { + // SUBPASS 1: DRAW STUFF + vk::SubpassDescription2 drawSubpass { .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, .colorAttachmentCount = 1, .pColorAttachments = &colorAttachmentRef, /* .pDepthStencilAttachment = &depthAttachmentRef, */ }; - vk::SubpassDependency2 colorAttachmentSD { + vk::SubpassDependency2 dsColorAttachmentSD { .srcSubpass = VK_SUBPASS_EXTERNAL, .dstSubpass = 0, .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, @@ -162,37 +205,46 @@ namespace gz::vlk { }; // dependecy for the 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, + /* vk::SubpassDependency2 dsLayoutTransitionSD { */ + /* .srcSubpass = 0, */ + /* .dstSubpass = 1, */ + /* .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, */ + /* .dstStageMask = vk::PipelineStageFlagBits::eTransfer, */ + /* .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, */ + /* .dstAccessMask = vk::AccessFlagBits::eTransferRead, */ + /* .dependencyFlags = vk::DependencyFlagBits::eByRegion, */ + /* }; */ + + // SUBPASS 2: BLIT ONTO SWAP CHAIN IMAGE + vk::SubpassDescription2 blitSubpass { + .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, + .colorAttachmentCount = 1, + .pColorAttachments = &colorAttachmentRef, + }; + + vk::SubpassDependency2 bsColorAttachmentSD { + .srcSubpass = 0, + .dstSubpass = 1, + .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, + .dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, + .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, + .dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead, }; - /* vk::SubpassDependency 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::array attachments = { colorBlendAttachment, depthAttachment }; */ std::vector attachments = { colorBlendAttachment }; - std::vector dependencies = { colorAttachmentSD, layoutTransitionSD }; + std::vector subpasses { drawSubpass, blitSubpass }; + std::vector dependencies = { dsColorAttachmentSD, bsColorAttachmentSD }; //dsLayoutTransitionSD }; vk::RenderPassCreateInfo2 renderPassCI; - renderPassCI.setDependencies(dependencies); renderPassCI.setAttachments(attachments); - renderPassCI.setSubpasses(subpass); + renderPassCI.setSubpasses(subpasses); + renderPassCI.setDependencies(dependencies); 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."); - } @@ -224,7 +276,7 @@ namespace gz::vlk { commandBuffers[currentFrame].beginRenderPass(&renderPassBI, vk::SubpassContents::eInline); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[PL_2D].pipeline); + commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[R2Render].pipeline); vk::Buffer vertexBuffers[] = { vertexBuffer }; vk::DeviceSize offsets[] = {0}; uint32_t bindingCount = 1; @@ -237,7 +289,7 @@ namespace gz::vlk { uint32_t firstSet = 0; uint32_t dynamicOffsetCount = 0; uint32_t* dynamicOffsets = nullptr; - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelines[PL_2D].layout, firstSet, descriptorCount, &textureManager.getDescriptorSet(), dynamicOffsetCount, dynamicOffsets); + commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelines[R2Render].layout, firstSet, descriptorCount, &textureManager.getDescriptorSet(), dynamicOffsetCount, dynamicOffsets); int instanceCount = 1; int firstIndex = 0; @@ -245,7 +297,7 @@ namespace gz::vlk { 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()); + /* vk.copyImageToImage(commandBuffers[currentFrame], images[imageIndex], vk.getScImages()[imageIndex], vk.getScExtent()); */ result = commandBuffers[currentFrame].end(); if (result != vk::Result::eSuccess) { rLog.error("Failed to record 2D - command buffer", "VkResult:", result); diff --git a/src/renderer/renderer2D.hpp b/src/renderer/renderer2D.hpp index f63b931..daa267d 100644 --- a/src/renderer/renderer2D.hpp +++ b/src/renderer/renderer2D.hpp @@ -7,6 +7,10 @@ #include "vulkan_util.hpp" namespace gz::vlk { + enum Pipelines2D { + R2Render, + }; + class Renderer2D : public Renderer { public: /** @@ -60,20 +64,21 @@ namespace gz::vlk { */ void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame); - // IMAGE /** - * @name Image (render targets) + * @brief Create the render image resources * @details - * The images are used as render targets. After rendering, the current image gets blitted onto the current swap chain image. - * @{ + * If `RENDERER_2D_RENDER_TO_SWAP_CHAIN`: + * - renderImages are null handles + * - renderImageMemory are null handles + * - renderImageViews are views to VulkanInstance::getScImages() + * - renderImageSampler is null handle + * + * Else: + * - renderImages are images on renderImageMemory + * - renderImageViews are views to renderImages + * - renderImageSampler is a combined image sampler */ - std::vector images; - std::vector imageMemory; - std::vector imageViews; - /** - * @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images - */ - void createImages(); + void createImageResources(); /// @} /** @@ -95,9 +100,13 @@ namespace gz::vlk { vk::RenderPass renderPass; /// @} + /** + * @brief Framebuffer for renderImageViews + */ std::vector framebuffers; + // PIPELINE - PipelineContainer pipelines; + PipelineContainer pipelines; // SWAPCHAIN RECREATION /** diff --git a/src/renderer/renderer3D.cpp b/src/renderer/renderer3D.cpp index a02ded1..b833ff9 100644 --- a/src/renderer/renderer3D.cpp +++ b/src/renderer/renderer3D.cpp @@ -8,8 +8,11 @@ #include "vk_enum_string.h" #include "vulkan_settings.hpp" +#include + #include #include +#include namespace gz::vlk { // @@ -41,11 +44,12 @@ namespace gz::vlk { createUniformBuffers(); createDescriptorResources(); initSwapChainDependantResources(); - VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan("Renderer3D", - { &pipelines[PL_3D].pipeline, &renderPass, &vertexBuffer, &vertexBufferMemory, &indexBuffer, &indexBufferMemory, - &descriptorSetLayout, &descriptorPool, }, - { &framebuffers, &images, &imageMemory, &imageViews, &commandBuffers, - &descriptorSets })); + VulkanInstance::registerObjectUsingVulkan("Renderer3D", + &renderPass, &imageSampler, &vertexBuffer, &vertexBufferMemory.memory, &indexBuffer, &indexBufferMemory.memory, + &pipelines[R3Render].pipeline, //&pipelines[blendToSC].pipeline, + &descriptorPool, &uboDSL, &sampleFromRenderImageDSL, + &framebuffers, &renderImages, &renderImageViews, &commandBuffers, + &uboDS, &sampleFromRenderImageDS); // missing: &renderImageMemory, rLog.log1("Created Renderer3D"); } @@ -55,7 +59,7 @@ namespace gz::vlk { for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) { vk.destroyBuffer(uniformBuffers[i], uniformBuffersMemory[i]); } - vk.getDevice().destroyDescriptorSetLayout(descriptorSetLayout, NO_ALLOC); + vk.getDevice().destroyDescriptorSetLayout(uboDSL, NO_ALLOC); vk.getDevice().destroyDescriptorPool(descriptorPool, NO_ALLOC); cleanupSwapChainDependantResources(); @@ -69,27 +73,84 @@ namespace gz::vlk { void Renderer3D::initSwapChainDependantResources() { // UPDATE DOC ON CHANGES! createRenderPass(); - createImages(); 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]); + createImageResources(); + vk.createFramebuffers(framebuffers, renderImageViews, renderPass, depthImageView); + + // VERTEX 3D PIPELINE + std::vector descriptorSetLayouts = { uboDSL, textureManager.getDescriptorSetLayout() }; + auto vertShaderCode = readBinaryFile("shaders/shader.vert.spv"); + auto fragShaderCode = readBinaryFile("shaders/shader.frag.spv"); + + vk::ShaderModule vertShaderModule = vk.createShaderModule(vertShaderCode); + vk::ShaderModule fragShaderModule = vk.createShaderModule(fragShaderCode); + + std::vector shaderStages; + + shaderStages.emplace_back(vk::PipelineShaderStageCreateInfo { + .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertShaderModule, + .pName = "main", + .pSpecializationInfo = nullptr, + }); + shaderStages.emplace_back(vk::PipelineShaderStageCreateInfo { + .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragShaderModule, + .pName = "main", + .pSpecializationInfo = nullptr, + }); + + vk::GraphicsPipelineCreateInfo pipelineCI { + .renderPass = renderPass, + .subpass = 0, + }; + pipelineCI.setStages(shaderStages); + + vk.createGraphicsPipeline(std::move(pipelineCI), &descriptorSetLayouts, true, pipelines[R3Render]); + + vk.getDevice().destroyShaderModule(vertShaderModule, nullptr); + vk.getDevice().destroyShaderModule(fragShaderModule, nullptr); + + + // BLIT TO SWAP CHAIN PIPELINE + /* auto fragShaderCode2 = readBinaryFile("shaders/blend.frag.spv"); */ + /* vk::ShaderModule fragShaderModule2 = vk.createShaderModule(fragShaderCode); */ + + /* std::vector shaderStages2; */ + /* shaderStages2.emplace_back(vk::PipelineShaderStageCreateInfo { */ + /* .stage = vk::ShaderStageFlagBits::eFragment, */ + /* .module = fragShaderModule2, */ + /* .pName = "main", */ + /* .pSpecializationInfo = nullptr, */ + /* }); */ + + /* vk::GraphicsPipelineCreateInfo pipelineCI2 { */ + /* .renderPass = renderPass, */ + /* .subpass = 1, */ + /* }; */ + /* pipelineCI2.setStages(shaderStages2); */ + + /* vk.createGraphicsPipeline(std::move(pipelineCI2), nullptr, false, pipelines[blendToSC]); */ + + /* vk.getDevice().destroyShaderModule(fragShaderModule2, nullptr); */ } void Renderer3D::cleanupSwapChainDependantResources() { // destroy pipelines - pipelines.destroy(vk.getDevice()); + pipelines.clear(vk.getDevice()); 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]); +#ifndef RENDERER_3D_RENDER_TO_SWAP_CHAIN + for (size_t i = 0; i < renderImages.size(); i++) { + vk.destroyImageView(renderImageViews[i]); + vk.destroyImage(renderImages[i], renderImageMemory[i]); } +#endif vk.getDevice().destroyRenderPass(renderPass, nullptr); } @@ -103,15 +164,24 @@ namespace gz::vlk { // // IMAGES // - void Renderer3D::createImages() { - images.resize(vk.getScImages().size()); - imageMemory.resize(vk.getScImages().size()); - imageViews.resize(vk.getScImages().size()); + void Renderer3D::createImageResources() { + renderImageViews.resize(vk.getScImages().size()); +#ifndef RENDERER_3D_RENDER_TO_SWAP_CHAIN + renderImages.resize(vk.getScImages().size()); + renderImageMemory.resize(vk.getScImages().size()); 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::ImageTiling::eOptimal, usage, vk::MemoryPropertyFlagBits::eDeviceLocal, images[i], imageMemory[i]); - vk.createImageView(vk.getScImageFormat(), images[i], imageViews[i], vk::ImageAspectFlagBits::eColor); + for (size_t i = 0; i < renderImages.size(); i++) { + vk.createImage(vk.getScExtent().width, vk.getScExtent().height, vk.getScImageFormat(), vk::ImageTiling::eOptimal, usage, vk::MemoryPropertyFlagBits::eDeviceLocal, renderImages[i], renderImageMemory[i]); + vk.createImageView(vk.getScImageFormat(), renderImages[i], renderImageViews[i], vk::ImageAspectFlagBits::eColor); } + vk.createTextureSampler(imageSampler); + rLog.log0("createImageResources: created images, views and sampler"); +#else + for (size_t i = 0; i < renderImages.size(); i++) { + vk.createImageView(vk.getScImageFormat(), vk.getScImages()[i], renderImageViews[i], vk::ImageAspectFlagBits::eColor); + } + rLog.log0("createImageResources: created image views"); +#endif } @@ -232,61 +302,56 @@ namespace gz::vlk { // DESCRIPTORS // void Renderer3D::createDescriptorResources() { - // LAYOUT - // 1) uniform buffer object - vk::DescriptorSetLayoutBinding uboLayoutBinding { + rLog("createDescriptorResources: pool", reinterpret_cast(static_cast(descriptorPool)), "vs hpp:", reinterpret_cast(&(*descriptorPool))); + // LAYOUTS + std::vector uboDSLB; + // SET 1: uniform buffer object + uboDSLB.emplace_back(vk::DescriptorSetLayoutBinding { .binding = 0, .descriptorType = vk::DescriptorType::eUniformBuffer, .descriptorCount = 1, .stageFlags = vk::ShaderStageFlagBits::eVertex, /* .pImmutableSamplers = nullptr, */ - }; + }); - // 2) combined image sampler - vk::DescriptorSetLayoutBinding samplerLayoutBinding { - .binding = 1, + /* // SET 1: combined image sampler */ + /* set1bindings.emplace_back(vk::DescriptorSetLayoutBinding { */ + /* .binding = 1, */ + /* .descriptorType = vk::DescriptorType::eCombinedImageSampler, */ + /* .descriptorCount = 1, */ + /* .stageFlags = vk::ShaderStageFlagBits::eFragment, */ + /* /1* .pImmutableSamplers = nullptr, *1/ */ + /* }); */ + vk.createDescriptorSetLayout(uboDSLB, uboDSL); + +#ifndef RENDERER_3D_RENDER_TO_SWAP_CHAIN + // SET 2: combined image sampler + std::vector sampleFromRenderImageDSLB; + sampleFromRenderImageDSLB.emplace_back(vk::DescriptorSetLayoutBinding { + .binding = 0, .descriptorType = vk::DescriptorType::eCombinedImageSampler, .descriptorCount = 1, .stageFlags = vk::ShaderStageFlagBits::eFragment, - /* .pImmutableSamplers = nullptr, */ - }; + }); + vk.createDescriptorSetLayout(sampleFromRenderImageDSLB, sampleFromRenderImageDSL); +#endif - std::vector bindings = { uboLayoutBinding, samplerLayoutBinding }; - vk.createDescriptorSetLayout(bindings, descriptorSetLayout); // POOL - std::array poolSizes; - poolSizes[0].type = vk::DescriptorType::eUniformBuffer; - poolSizes[0].descriptorCount = static_cast(vk.getMaxFramesInFlight()); - poolSizes[1].type = vk::DescriptorType::eCombinedImageSampler; - poolSizes[1].descriptorCount = static_cast(vk.getMaxFramesInFlight()); - - vk::DescriptorPoolCreateInfo poolCI { - .maxSets = static_cast(vk.getMaxFramesInFlight()), + std::vector poolSizes; + poolSizes = { + { .type = vk::DescriptorType::eUniformBuffer, .descriptorCount = vk.getMaxFramesInFlight() }, +#ifndef RENDERER_3D_RENDER_TO_SWAP_CHAIN + { .type = vk::DescriptorType::eCombinedImageSampler, .descriptorCount = vk.getMaxFramesInFlight() }, +#endif }; - 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"); - } + vk.createDescriptorPool(poolSizes, vk.getMaxFramesInFlight(), descriptorPool); // SETS - std::vector layouts(vk.getMaxFramesInFlight(), descriptorSetLayout); - vk::DescriptorSetAllocateInfo setAI { - .descriptorPool = descriptorPool, - }; - setAI.setSetLayouts(layouts); + // SET 1 + std::vector layouts1(vk.getMaxFramesInFlight(), uboDSL); + vk.createDescriptorSets(layouts1, descriptorPool, uboDS); - // 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++) { vk::DescriptorBufferInfo bufferI { .buffer = uniformBuffers[i], @@ -294,32 +359,46 @@ namespace gz::vlk { .range = VK_WHOLE_SIZE, // sizeof(UniformBufferObject), }; - vk::DescriptorImageInfo imageI { - .sampler = textureManager.getTextureAtlas().getTextureSampler(), - .imageView = textureManager.getTextureAtlas().getTextureImageView(), - .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal, + vk::WriteDescriptorSet descriptorW{ + .dstSet = uboDS[i], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = vk::DescriptorType::eUniformBuffer, + .pBufferInfo = &bufferI, }; - - std::array descriptorW{}; - descriptorW[0].dstSet = descriptorSets[i]; - descriptorW[0].dstBinding = bindingUniformBuffer; - descriptorW[0].dstArrayElement = 0; - descriptorW[0].descriptorType = vk::DescriptorType::eUniformBuffer; - descriptorW[0].setBufferInfo(bufferI); - /* descriptorW[0].pImageInfo = nullptr; */ /* descriptorW[0].pTexelBufferView = nullptr; */ - - descriptorW[1].dstSet = descriptorSets[i]; - descriptorW[1].dstBinding = bindingCombinedImageSampler; - descriptorW[1].dstArrayElement = 0; - descriptorW[1].descriptorType = vk::DescriptorType::eCombinedImageSampler; - descriptorW[1].setImageInfo(imageI); - /* descriptorW[1].pTexelBufferView = nullptr; */ // write 1, copy 0 vk.getDevice().updateDescriptorSets(descriptorW, nullptr); - } - rLog.log0("createDescriptorResources: Created descriptor layouts, pool and sets."); + } // for + rLog.log0("createDescriptorResources: Created descriptor layout and sets for uniform buffer"); + +#ifndef RENDERER_3D_RENDER_TO_SWAP_CHAIN + // SET 2: + std::vector layouts2(vk.getMaxFramesInFlight(), sampleFromRenderImageDSL); + vk.createDescriptorSets(layouts2, descriptorPool, sampleFromRenderImageDS); + + for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) { + vk::DescriptorImageInfo imageI { + .sampler = imageSampler, + .imageView = renderImageViews[i], + .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal, + }; + + vk::WriteDescriptorSet descriptorW{ + .dstSet = sampleFromRenderImageDS[i], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = vk::DescriptorType::eCombinedImageSampler, + .pImageInfo = &imageI, + }; + // write 1, copy 0 + vk.getDevice().updateDescriptorSets(descriptorW, nullptr); + } // for + rLog.log0("createDescriptorResources: Created descriptor layout and sets for sampling from renderImages"); +#endif } // @@ -397,7 +476,7 @@ namespace gz::vlk { commandBuffers[currentFrame].beginRenderPass(renderPassBI, vk::SubpassContents::eInline); - commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[PL_3D].pipeline); + commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[R3Render].pipeline); vk::Buffer vertexBuffers[] = { vertexBuffer }; vk::DeviceSize offsets[] = {0}; uint32_t bindingCount = 1; @@ -407,15 +486,21 @@ namespace gz::vlk { commandBuffers[currentFrame].bindIndexBuffer(indexBuffer, NO_OFFSET, vk::IndexType::eUint32); uint32_t firstSet = 0; - commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelines[PL_3D].layout, firstSet, descriptorSets[currentFrame], {}); + std::vector descriptorSets = { uboDS[currentFrame], textureManager.getDescriptorSet() }; + commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelines[R3Render].layout, firstSet, descriptorSets, {}); int instanceCount = 1; int firstIndex = 0; int firstInstance = 0; commandBuffers[currentFrame].drawIndexed(static_cast(model.indices.size()), instanceCount, firstIndex, NO_OFFSET, firstInstance); + + /* commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[blendToSC].pipeline); */ + /* commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelines[blendToSC].layout, firstSet, sampleFromRenderImageDS[currentFrame], {}); */ + /* // draw hardcoded fullscreen quad */ + /* commandBuffers[currentFrame].draw(6, 1, 0, 0); */ commandBuffers[currentFrame].endRenderPass(); - vk.copyImageToImage(commandBuffers[currentFrame], images[imageIndex], vk.getScImages()[imageIndex], vk.getScExtent()); + vk.copyImageToImage(commandBuffers[currentFrame], renderImages[imageIndex], vk.getScImages()[imageIndex], vk.getScExtent()); result = commandBuffers[currentFrame].end(); if (result != vk::Result::eSuccess) { rLog.error("Failed to record 3D - command buffer", "VkResult:", result); @@ -470,9 +555,4 @@ namespace gz::vlk { vk.getDevice().unmapMemory(uniformBufferMI.memory); } - - - - - } // namespace gz::vlk diff --git a/src/renderer/renderer3D.hpp b/src/renderer/renderer3D.hpp index 07f6df8..c86b04e 100644 --- a/src/renderer/renderer3D.hpp +++ b/src/renderer/renderer3D.hpp @@ -12,6 +12,10 @@ namespace gz::vlk { alignas(16) glm::mat4 projection; }; + enum Pipelines3D { + R3Render, + }; + class Renderer3D : public Renderer { public: /** @@ -40,22 +44,24 @@ namespace gz::vlk { void updateUniformBuffer(); /** - * @name Image (render targets) + * @brief Create the render image resources * @details - * 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 imageMemory; - std::vector imageViews; - /** - * @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images - */ - void createImages(); - /// @} - /** - * @name Depth + * If `RENDERER_3D_RENDER_TO_SWAP_CHAIN`: + * - renderImages are null handles + * - renderImageMemory are null handles + * - renderImageViews are views to VulkanInstance::getScImages() + * - renderImageSampler is null handle + * + * Else: + * - renderImages are images on renderImageMemory + * - renderImageViews are views to renderImages + * - renderImageSampler is a combined image sampler */ + void createImageResources(); + + /** + * @name Depth + */ /// @{ vk::Image depthImage; MemoryInfo depthImageMemory; @@ -66,17 +72,33 @@ namespace gz::vlk { void createDepthImage(); /// @} - /** - * @name Render pass - * @details - * Attachments: - * - color blend: - * - loadOp = vk::AttachmentLoadOp::eClear - * - storeOp = vk::AttachmentStoreOp::eStore - * - initialLayout = vk::ImageLayout::eColorAttachmentOptimal - * - finalLayout = vk::ImageLayout::eColorAttachmentOptimal - * - stencil load/store = dont care - */ + /** + * @name Render pass + * @details + * @section r3p_rp Render pass + * @subsection r3p_subpass1 Subpass 1: Rendering + * Attributes: + * - Pipeline: `Pipelines3D::R3Render` + * - Descriptor layouts: `@ref r3p_desc1 "descriptorSet1Layout"` and `@ref tm_desc "TextureManager::descriptorSetLayout"` + * - Attachments: + * - color blend: + * - loadOp = vk::AttachmentLoadOp::eClear + * - storeOp = vk::AttachmentStoreOp::eStore + * - initialLayout = vk::ImageLayout::eColorAttachmentOptimal + * - finalLayout = vk::ImageLayout::eColorAttachmentOptimal + * - stencil load/store = dont care + * @subsection r3p_subpass2 Subpass 2: Blitting render image onto swap chain image + * Attributes: + * - Pipeline: `Pipelines3D::blendToSC` + * - Descriptor layouts: `@ref r3p_desc2 "descriptorSet2Layout"` + * - Attachments: + * - color blend: + * - loadOp = vk::AttachmentLoadOp::eClear + * - storeOp = vk::AttachmentStoreOp::eStore + * - initialLayout = vk::ImageLayout::eColorAttachmentOptimal + * - finalLayout = vk::ImageLayout::eColorAttachmentOptimal + * - stencil load/store = dont care + */ /// @{ /** * @brief Create a render pass @@ -87,39 +109,37 @@ namespace gz::vlk { std::vector framebuffers; // PIPELINE - PipelineContainer pipelines; + PipelineContainer pipelines; - /** - * @name Desciptors - * @details These functions create a desciptor with bindings for - * -# UniformBufferObject (DESCRIPTOR_TYPE_UNIFORM_BUFFER) - * -# Combined Image Sampler (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) - */ + /** + * @name Desciptors + * @details + * + * @section r3d_desc Descriptors + * Renderer3D has two descriptor sets, both allocated from the same pool. + * @subsection r3d_desc1 Set 1: For rendering + * Bindings: + * -0. UniformBufferObject (DESCRIPTOR_TYPE_UNIFORM_BUFFER) + * @subsection r3d_desc2 Set 2: For sampling from the rendered image (only if not `RENDERER_3D_RENDER_TO_SWAP_CHAIN) + * -0. Image sampler for current render image (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) + */ /// @{ vk::DescriptorPool descriptorPool; - vk::DescriptorSetLayout descriptorSetLayout; - std::vector descriptorSets; + + vk::DescriptorSetLayout uboDSL; + std::vector uboDS; + + vk::DescriptorSetLayout sampleFromRenderImageDSL; + std::vector sampleFromRenderImageDS; /** - * @brief Create a descriptor layout binding for the MVP uniform buffer object - * @details Create a desciptor set layout with bindings for - * -# UniformBufferObject (DESCRIPTOR_TYPE_UNIFORM_BUFFER) - * -# Combined Image Sampler (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) + * @brief Create @ref r3d_desc "all descritptor resources" */ - void createDescriptorPool(); - /* - * @bried Create one descriptor set with layout descriptorSetLayout for each frame - */ - void createDescriptorSets(); - const uint32_t bindingUniformBuffer = 0; - const uint32_t bindingCombinedImageSampler = 1; - /* const uint32_t bindingCombinedImageSampler = 1; */ - - void createDescriptorResources(); + /// @} - /** - * @brief Swapchain recreation - */ + /** + * @name Swapchain recreation + */ /// @{ /** * @brief Cleans up resources that were initialized by initSwapChainDependantResources @@ -133,7 +153,8 @@ namespace gz::vlk { * - @ref createImages() "images and imageViews" * - @ref createDepthImage() "depth image and view" * - @ref VulkanInstance::createFramebuffers() "framebuffers" - * - pipeline + * - pipelines: + * - R3Render */ void initSwapChainDependantResources(); /** diff --git a/src/utility/texture_atlas.cpp b/src/utility/texture_atlas.cpp index 63ad7bb..562514c 100644 --- a/src/utility/texture_atlas.cpp +++ b/src/utility/texture_atlas.cpp @@ -43,9 +43,8 @@ TextureAtlas::TextureAtlas(VulkanInstance& instance, uint16_t slotWidth, uint16_ freeAreas.insert({ 0, 0, slotCountX, slotCountY}); createImageResources(); /* vk.registerCleanupCallback(std::bind(&TextureAtlas::cleanup, this)); */ - VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan(std::string("TextureAtlas-") + gz::toString(slotWidth) + "x" + gz::toString(slotHeight), - { &textureImage, &textureImageMemory, &textureImageView, &textureSampler }, - {})); + VulkanInstance::registerObjectUsingVulkan(std::string("TextureAtlas-") + gz::toString(slotWidth) + "x" + gz::toString(slotHeight), + &textureImage, &textureImageMemory.memory, &textureImageView, &textureSampler); } diff --git a/src/utility/texture_manager.cpp b/src/utility/texture_manager.cpp index 480e219..d2b8089 100644 --- a/src/utility/texture_manager.cpp +++ b/src/utility/texture_manager.cpp @@ -19,12 +19,9 @@ namespace gz::vlk { vk.registerCleanupCallback(std::bind(&TextureManager::cleanup, this)); atlases.emplace_back(TextureAtlas(vk, 24, 24, 24, 24)); - createDescriptorSetLayout(); - createDescriptorPool(); - createDescriptorSet(); - VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan("TextureManager", - { &descriptorSetLayout, &descriptorPool, &descriptorSet }, - {})); + createDescriptorResources(); + VulkanInstance::registerObjectUsingVulkan("TextureManager", + &descriptorSetLayout, &descriptorPool, &descriptorSet); } @@ -69,79 +66,50 @@ namespace gz::vlk { // // DESCRIPTOR SET // -void TextureManager::createDescriptorSetLayout() { - // combined image sampler - std::vector samplerLayoutBindings(atlases.size(), { - .binding = 0, - .descriptorType = vk::DescriptorType::eCombinedImageSampler, - .descriptorCount = 1, - .stageFlags = vk::ShaderStageFlagBits::eFragment, - /* .pImmutableSamplers = nullptr, */ - } - ); + void TextureManager::createDescriptorResources() { + // 1) layout + // combined image sampler + std::vector samplerLayoutBindings(atlases.size(), { + .binding = 0, + .descriptorType = vk::DescriptorType::eCombinedImageSampler, + .descriptorCount = 1, + .stageFlags = vk::ShaderStageFlagBits::eFragment, + /* .pImmutableSamplers = nullptr, */ + } + ); + vk.createDescriptorSetLayout(samplerLayoutBindings, descriptorSetLayout); - vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCI; - descriptorSetLayoutCI.setBindings(samplerLayoutBindings); - - 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."); */ -} - - -void TextureManager::createDescriptorPool() { - std::vector poolSizes { - vk::DescriptorPoolSize { + // 2) pool + vk::DescriptorPoolSize poolSize { .type = vk::DescriptorType::eCombinedImageSampler, - .descriptorCount = static_cast(vk.getMaxFramesInFlight()) + .descriptorCount = vk.getMaxFramesInFlight(), + }; + vk.createDescriptorPool({ poolSize }, vk.getMaxFramesInFlight(), descriptorPool); + + // 3) Set + vk.createDescriptorSet(descriptorSetLayout, descriptorPool, descriptorSet); + + // 4) configure sets + std::vector imageInfos; + for (auto it = atlases.cbegin(); it != atlases.cend(); it++) { + imageInfos.emplace_back(); + imageInfos.back().imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal; + imageInfos.back().imageView = it->getTextureImageView(); + imageInfos.back().sampler = it->getTextureSampler(); } - }; - 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() { - vk::DescriptorSetAllocateInfo setAI { - .descriptorPool = descriptorPool, - }; - setAI.setSetLayouts(descriptorSetLayout); - - 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"); + vk::WriteDescriptorSet descriptorW { + .dstSet = descriptorSet, + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = vk::DescriptorType::eCombinedImageSampler, + }; + descriptorW.setImageInfo(imageInfos); + + // 1 write, no copies + vk.getDevice().updateDescriptorSets(descriptorW, nullptr); + tLog.log0("createDescriptorSets: Created descriptor sets."); } - // configure sets - std::vector imageInfos; - for (auto it = atlases.cbegin(); it != atlases.cend(); it++) { - imageInfos.emplace_back(); - imageInfos.back().imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - imageInfos.back().imageView = it->getTextureImageView(); - imageInfos.back().sampler = it->getTextureSampler(); - } - - vk::WriteDescriptorSet descriptorW { - .dstSet = descriptorSet, - .dstBinding = 0, - .dstArrayElement = 0, - .descriptorType = vk::DescriptorType::eCombinedImageSampler, - }; - descriptorW.setImageInfo(imageInfos); - - // 1 write, no copies - vk.getDevice().updateDescriptorSets(descriptorW, nullptr); - tLog.log0("createDescriptorSets: Created descriptor sets."); -} } // namespace gz::vlk diff --git a/src/utility/texture_manager.hpp b/src/utility/texture_manager.hpp index 389ccff..bf71533 100644 --- a/src/utility/texture_manager.hpp +++ b/src/utility/texture_manager.hpp @@ -58,14 +58,12 @@ namespace gz::vlk { vk::DescriptorSet descriptorSet; /* std::vector descriptorSets; */ /** - * @brief Create a descriptor set layout + * @brief Create a descriptor set, layout and pool * @details * Bindings: - * -0 COMBINED_IMAGE_SAMPLER + * -0. texture sampler array COMBINED_IMAGE_SAMPLER[atlasCount] */ - void createDescriptorSetLayout(); - void createDescriptorPool(); - void createDescriptorSet(); + void createDescriptorResources(); /* const uint32_t bindingCombinedImageSampler = 1; */ /** diff --git a/src/vulkan_allocator.hpp b/src/vulkan_allocator.hpp index 015fe51..8af4508 100644 --- a/src/vulkan_allocator.hpp +++ b/src/vulkan_allocator.hpp @@ -1,6 +1,6 @@ #pragma once -/* #include "vulkan_util.hpp" */ +#include "vulkan_util.hpp" #include #include diff --git a/src/vulkan_instance.cpp b/src/vulkan_instance.cpp index de879f0..f9e2d1e 100644 --- a/src/vulkan_instance.cpp +++ b/src/vulkan_instance.cpp @@ -8,7 +8,10 @@ #include #include #include +#include #include +#include +#include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" @@ -59,9 +62,10 @@ using std::uint32_t; if (glfwVulkanSupported() == GLFW_FALSE) { throw std::runtime_error("Vulkan not supported."); } - VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan("VulkanInstance", - { &instance, &physicalDevice, &device, &graphicsQ, &presentQ, &transferQ, &commandPoolGraphics, &commandPoolTransfer, &surface, &swapChain }, - { &scImages, &scImageViews, &commandBuffersBegin, &commandBuffersEnd })); + + VulkanInstance::registerObjectUsingVulkan("VulkanInstance", + &instance, &physicalDevice, &device, &graphicsQ, &presentQ, &transferQ, &commandPoolGraphics, &commandPoolTransfer, &surface, &swapChain, + &scImages, &scImageViews, &commandBuffersBegin, &commandBuffersEnd); createInstance(); setupDebugMessenger(); createSurface(); @@ -71,7 +75,6 @@ using std::uint32_t; createLogicalDevice(); createSwapChain(); - createSwapChainImageViews(); createCommandPools(); createCommandBuffers(commandBuffersBegin); @@ -81,7 +84,7 @@ using std::uint32_t; /* createDescriptorSets(); // after UniformBuffers */ for (auto& obj : VulkanInstance::objectsUsingVulkan) { - obj.updateHandles(); + obj->updateHandles(); } } @@ -165,8 +168,10 @@ using std::uint32_t; // transition to transfer dst layout transitionImageLayout(scImages[imageIndex], scImageFormat, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, &commandBuffersBegin[currentFrame]); vk::ImageMemoryBarrier2 imageBarrier { - .srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe, + .srcStageMask = vk::PipelineStageFlagBits2::eNone, + .srcAccessMask = vk::AccessFlagBits2::eNone, .dstStageMask = vk::PipelineStageFlagBits2::eTransfer, + .dstAccessMask = vk::AccessFlagBits2::eTransferWrite, .oldLayout = vk::ImageLayout::eUndefined, .newLayout = vk::ImageLayout::eTransferDstOptimal, .image = scImages[imageIndex], @@ -249,11 +254,6 @@ using std::uint32_t; } - void VulkanInstance::registerObjectUsingVulkan(const ObjectUsingVulkan& obj) { - objectsUsingVulkan.push_back(obj); - } - - // PUBLIC INTERFACE: VARIOUS UTILITY @@ -395,45 +395,19 @@ using std::uint32_t; commandBuffers.resize(0); } - - // DESCRIPTORS SET LAYOUTS - void VulkanInstance::createDescriptorSetLayout(std::vector bindings, vk::DescriptorSetLayout& layout) { - vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCI; - descriptorSetLayoutCI.setBindings(bindings); - - 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."); */ - } - - // GRAPHICS 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) { - auto vertShaderCode = readFile(vertexShader); - auto fragShaderCode = readFile(fragmentShader); - - vk::ShaderModule vertShaderModule = createShaderModule(vertShaderCode); - vk::ShaderModule fragShaderModule = createShaderModule(fragShaderCode); - - vk::PipelineShaderStageCreateInfo vertexShaderStageCI { - .stage = vk::ShaderStageFlagBits::eVertex, - .module = vertShaderModule, - .pName = "main", - .pSpecializationInfo = vertSI, - }; - - vk::PipelineShaderStageCreateInfo fragmentShaderStageCI { - .stage = vk::ShaderStageFlagBits::eFragment, - .module = fragShaderModule, - .pName = "main", - .pSpecializationInfo = fragSI, - }; - - vk::PipelineShaderStageCreateInfo shaderStagesCI[] = { vertexShaderStageCI, fragmentShaderStageCI }; + void VulkanInstance::createGraphicsPipeline(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline) { + // 1) sanity checks + if (pipelineCI.pStages == nullptr) { + throw VkUserError("pStages is nullptr", "VulkanInstance::createGraphicsPipeline"); + } + if (static_cast(pipelineCI.renderPass) == VK_NULL_HANDLE) { + throw VkUserError("renderPass is VK_NULL_HANDLE", "VulkanInstance::createGraphicsPipeline"); + } + // 2) construct default create infos + // default vertexInputStateCI vk::VertexInputBindingDescription bindingD = VertexT::getBindingDescription(); // array auto attributeD = VertexT::getAttributeDescriptions(); @@ -442,11 +416,13 @@ using std::uint32_t; vertexInputStateCI.setVertexAttributeDescriptions(attributeD); vertexInputStateCI.setVertexBindingDescriptions(bindingD); + // default inputAssemblyStateCI vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCI { .topology = vk::PrimitiveTopology::eTriangleList, .primitiveRestartEnable = VK_FALSE, }; + // default viewportState vk::Viewport viewport { .x = 0.0f, .y = 0.0f, @@ -457,7 +433,7 @@ using std::uint32_t; }; vk::Rect2D scissor { - .offset = {0, 0}, + .offset = { 0, 0 }, .extent = scExtent, }; @@ -468,7 +444,8 @@ using std::uint32_t; .pScissors = &scissor, }; - vk::PipelineRasterizationStateCreateInfo rasterizerCI { + // default rasterizationState + vk::PipelineRasterizationStateCreateInfo rasterizationStateCI { .depthClampEnable = VK_FALSE, .rasterizerDiscardEnable = VK_FALSE, .polygonMode = vk::PolygonMode::eFill, @@ -482,6 +459,7 @@ using std::uint32_t; /* .depthBiasSlopeFactor = 0.0f, */ }; + // default multisampleStateCI vk::PipelineMultisampleStateCreateInfo multisampleStateCI { .rasterizationSamples = vk::SampleCountFlagBits::e1, .sampleShadingEnable = VK_FALSE, @@ -491,25 +469,27 @@ using std::uint32_t; /* .alphaToOneEnable = VK_FALSE, */ }; + // default colorBlendStateCI 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, */ + /* .blendEnable = VK_FALSE, */ + .blendEnable = VK_TRUE, + .srcColorBlendFactor = vk::BlendFactor::eOne, + .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, + .colorBlendOp = vk::BlendOp::eAdd, + .srcAlphaBlendFactor = vk::BlendFactor::eOne, + .dstAlphaBlendFactor = vk::BlendFactor::eOne, + .alphaBlendOp = vk::BlendOp::eAdd, .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, }; - vk::PipelineColorBlendStateCreateInfo colorBlendCI { + vk::PipelineColorBlendStateCreateInfo colorBlendStateCI { .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; + colorBlendStateCI.setAttachments(colorBlendAttachment); + colorBlendStateCI.blendConstants[0] = 0.0f; + colorBlendStateCI.blendConstants[1] = 0.0f; + colorBlendStateCI.blendConstants[2] = 0.0f; + colorBlendStateCI.blendConstants[3] = 0.0f; /* std::vector dynamicStates = { */ /* vk::DynamicState::eViewport, */ @@ -519,7 +499,8 @@ using std::uint32_t; /* dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); */ /* dynamicState.pDynamicStates = dynamicStates.data(); */ - vk::PipelineDepthStencilStateCreateInfo depthStencilCI { + // default depthStencilStateCI + vk::PipelineDepthStencilStateCreateInfo depthStencilStateCI { .depthTestEnable = VK_TRUE, .depthWriteEnable = VK_TRUE, .depthCompareOp = vk::CompareOp::eLess, @@ -532,45 +513,38 @@ using std::uint32_t; }; vk::PipelineLayoutCreateInfo pipelineLayoutCI; + // TODO /* pipelineLayoutCI.setPushConstantRanges() */ - pipelineLayoutCI.setSetLayouts(descriptorSetLayouts); + + if (descriptorSetLayouts != nullptr) { + 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"); } - 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); + pipelineCI.setLayout(pipeline.layout); + + if (pipelineCI.pVertexInputState == nullptr) { pipelineCI.setPVertexInputState(&vertexInputStateCI); } + if (pipelineCI.pInputAssemblyState == nullptr) { pipelineCI.setPInputAssemblyState(&inputAssemblyStateCI); } + if (pipelineCI.pViewportState == nullptr) { pipelineCI.setPViewportState(&viewportStateCI); } + if (pipelineCI.pRasterizationState == nullptr) { pipelineCI.setPRasterizationState(&rasterizationStateCI); } + if (pipelineCI.pMultisampleState == nullptr) { pipelineCI.setPMultisampleState(&multisampleStateCI); } + if (useDepthStencil and pipelineCI.pDepthStencilState == nullptr) { pipelineCI.setPDepthStencilState(&depthStencilStateCI); } + if (pipelineCI.pColorBlendState == nullptr) { pipelineCI.setPColorBlendState(&colorBlendStateCI); } // result, vector - auto [result2, pipelines] = device.createGraphicsPipelines(VK_NULL_HANDLE, pipelineCI, NO_ALLOC); + 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"); } - 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, 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); - + template void VulkanInstance::createGraphicsPipeline(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline); + template void VulkanInstance::createGraphicsPipeline(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline); // SHADER MODULE @@ -587,6 +561,21 @@ using std::uint32_t; return shaderModule; } + /* void VulkanInstance::createShaderModules(const std::vector>& shaders, std::vector& shaderStages,) { */ + /* vk::ShaderStageFlagBits::eAll */ + /* for (auto& [filepath, specI] : shaders) { */ + /* if (filepath.contains()) */ + /* shaderStages.emplace_back(vk::PipelineShaderStageCreateInfo { */ + /* .stage = vk::ShaderStageFlagBits::eFragment, */ + /* .module = fragShaderModule, */ + /* .pName = "main", */ + /* .pSpecializationInfo = nullptr, */ + /* }); */ + + /* } */ + + /* } */ + // BUFFER void VulkanInstance::createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties, vk::Buffer& buffer, MemoryInfo& bufferMI, vk::SharingMode sharingMode, std::vector* qFamiliesWithAccess) { @@ -674,7 +663,7 @@ using std::uint32_t; // FRAMEBUFFERS void VulkanInstance::createFramebuffers(std::vector& framebuffers, std::vector& imageViews, vk::RenderPass& renderPass, vk::ImageView depthImageView) { - framebuffers.resize(scImageViews.size()); + framebuffers.resize(imageViews.size()); vk::FramebufferCreateInfo framebufferCI { .renderPass = renderPass, @@ -743,6 +732,61 @@ using std::uint32_t; } + // DESCRIPTORS + void VulkanInstance::createDescriptorSetLayout(const std::vector& bindings, vk::DescriptorSetLayout& layout) { + vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCI; + descriptorSetLayoutCI.setBindings(bindings); + + vk::Result result; + std::tie(result, layout) = device.createDescriptorSetLayout(descriptorSetLayoutCI, NO_ALLOC); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Could not create descriptorSetLayout", "VulkanInstance::createDescriptorSetLayout"); + } + vLog.log0("createDescriptorSetLayout: Created descriptor set layout with", bindings.size(), "bindings"); + } + + + void VulkanInstance::createDescriptorPool(const std::vector& poolSizes, uint32_t maxSets, vk::DescriptorPool& pool) { + vk::DescriptorPoolCreateInfo poolCI { .maxSets = maxSets }; + poolCI.setPoolSizes(poolSizes); + + vk::Result result; + std::tie(result, pool) = device.createDescriptorPool(poolCI); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create descriptor pool", "VulkanInstance::createDescriptorPool"); + } + + vLog.log0("createDescriptorResources: Created descriptor pool with maxSets", maxSets, "and", poolSizes.size(), "pool sizes"); + } + + void VulkanInstance::createDescriptorSet(const vk::DescriptorSetLayout& layout, const vk::DescriptorPool& pool, vk::DescriptorSet& set) { + vk::DescriptorSetAllocateInfo setAI { + .descriptorPool = pool, + }; + setAI.setSetLayouts(layout); + + auto [result, sets] = device.allocateDescriptorSets(setAI); + set = sets.front(); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create descriptor set", "VulkanInstance::createDescriptorSet"); + } + } + + + void VulkanInstance::createDescriptorSets(const std::vector& layouts, const vk::DescriptorPool& pool, std::vector& sets) { + vk::DescriptorSetAllocateInfo setAI { + .descriptorPool = pool, + }; + setAI.setSetLayouts(layouts); + + vk::Result result; + std::tie(result, sets) = device.allocateDescriptorSets(setAI); + if (result != vk::Result::eSuccess) { + throw getVkException(result, "Failed to create descriptor set", "VulkanInstance::createDescriptorSet"); + } + } + + // PUBLIC INTERFACE: IMAGE UTILITY 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 { @@ -782,7 +826,7 @@ using std::uint32_t; 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); + vLog.log0("createImage: created and bound image of size", memoryAI.allocationSize, "with format", format, "and extent", imageCI.extent); } @@ -875,8 +919,6 @@ using std::uint32_t; } 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 @@ -895,50 +937,45 @@ using std::uint32_t; InstanceCommandPool commandPool; 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::ImageAspectFlagBits::eStencil; } - - barrier.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.srcAccessMask = vk::AccessFlagBits2::eNone; barrier.dstStageMask = vk::PipelineStageFlagBits2::eEarlyFragmentTests; + barrier.dstAccessMask = vk::AccessFlagBits2::eDepthStencilAttachmentRead | vk::AccessFlagBits2::eDepthStencilAttachmentWrite; commandPool = POOL_GRAPHICS; } 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::PipelineStageFlagBits2::eTopOfPipe; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.srcAccessMask = vk::AccessFlagBits2::eNone; barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; commandPool = POOL_TRANSFER; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; commandPool = POOL_GRAPHICS; } else if (oldLayout == vk::ImageLayout::eShaderReadOnlyOptimal and newLayout == vk::ImageLayout::eTransferDstOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits2::eShaderRead; - barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - barrier.srcStageMask = vk::PipelineStageFlagBits2::eFragmentShader; + barrier.srcAccessMask = vk::AccessFlagBits2::eShaderRead; barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; commandPool = POOL_GRAPHICS; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and newLayout == vk::ImageLayout::ePresentSrcKHR) { + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; barrier.dstAccessMask = vk::AccessFlagBits2::eMemoryRead; - - barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; barrier.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput; commandPool = POOL_GRAPHICS; } @@ -1489,9 +1526,10 @@ using std::uint32_t; .imageColorSpace = surfaceFormat.surfaceFormat.colorSpace, .imageExtent = scExtent, .imageArrayLayers = 1, - // if postProcessing: vk::ImageUsageFlagBits::eTransferDst + // transferDst for copying rendered images to swap chain .imageUsage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst, .preTransform = scDetails.capabilities.surfaceCapabilities.currentTransform, + // TODO .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque, .presentMode = selectSwapChainPresentMode(scDetails.presentModes), .clipped = VK_TRUE, @@ -1522,7 +1560,14 @@ using std::uint32_t; if (result != vk::Result::eSuccess) { throw getVkException(result, "Couldn not get swap chain images", "VulkanInstance::createSwapChain"); } - vLog.log0("createSwapChain: Created swap chain."); + + // create image views + scImageViews.resize(scImages.size()); + for (unsigned int i = 0; i < scImageViews.size(); i++) { + createImageView(scImageFormat, scImages[i], scImageViews[i], vk::ImageAspectFlagBits::eColor); + } + + vLog.log0("createSwapChain: Created swap chain with", scImages.size(), "images with format", swapChainCI.imageFormat, "extent", swapChainCI.imageExtent, "and color space", swapChainCI.imageColorSpace); } @@ -1541,7 +1586,6 @@ using std::uint32_t; cleanupSwapChain(); createSwapChain(); - createSwapChainImageViews(); createCommandBuffers(commandBuffersBegin); createCommandBuffers(commandBuffersEnd); @@ -1552,7 +1596,7 @@ using std::uint32_t; } vLog.log0("recreateSwapChain: Updating all ObjectsUsingVulkan"); for (auto& obj : VulkanInstance::objectsUsingVulkan) { - obj.updateHandles(); + obj->updateHandles(); } } @@ -1564,15 +1608,6 @@ using std::uint32_t; 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::ImageAspectFlagBits::eColor); - } - vLog.log0("createImageViews: Created", scImageViews.size(), "image views."); - } - uint32_t VulkanInstance::findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties) { for (uint32_t i = 0; i < phDevMemProperties.memoryProperties.memoryTypeCount; i++) { @@ -1648,27 +1683,6 @@ using std::uint32_t; } -// SHADERS - std::vector VulkanInstance::readFile(const std::string& filename) { - std::ifstream file(filename, std::ios::ate | std::ios::binary); - - std::vector buffer; - if (file.is_open()) { - size_t fileSize = file.tellg(); - buffer.resize(fileSize); - file.seekg(0); - file.read(buffer.data(), fileSize); - - } - else { - vLog.error("readFile: Failed to read file:", filename); - } - file.close(); - - return buffer; - } - - // DEBUG void VulkanInstance::setupDebugMessenger() { // get the address of the vkCreateDebugUtilsMessengerEXT function @@ -1704,7 +1718,7 @@ using std::uint32_t; // HANDLE OWNERSHIP bool VulkanInstance::lastColorWhite; - std::vector VulkanInstance::objectsUsingVulkan; + std::vector> VulkanInstance::objectsUsingVulkan; const std::regex reAddress(R"(0x[0-9a-f]+)"); std::string VulkanInstance::handleOwnerString(100, ' '); // reserve size 100 @@ -1722,8 +1736,8 @@ using std::uint32_t; ss >> address; for (auto& obj : objectsUsingVulkan) { /* vLog(address, obj.handles); */ - if (obj.handles.contains(address)) { - handleOwnerString += it->str() + " - " + obj.objectName; + if (obj->contains(address)) { + handleOwnerString += it->str() + " - " + obj->getName(); address = 0; foundHandle = true; } diff --git a/src/vulkan_instance.hpp b/src/vulkan_instance.hpp index 9a2fade..cafef8f 100644 --- a/src/vulkan_instance.hpp +++ b/src/vulkan_instance.hpp @@ -1,5 +1,6 @@ #pragma once +#include #define GLM_FORCE_DEPTH_ZERO_TO_ONE /* #include */ @@ -14,8 +15,8 @@ #include "vertex.hpp" #include "vulkan_util.hpp" -#include "vulkan_allocator.hpp" +#include "vulkan_allocator.hpp" #include "vulkan_settings.hpp" #include @@ -67,7 +68,6 @@ namespace gz::vlk { * -# @ref setValidSettings "set the possible settings for the SettingsManager" * -# @ref createLogicalDevice "create a logical device" * -# @ref createSwapChain "create the swap chain" - * -# @ref createSwapChainImageViews "create the swap chain image views" * -# @ref createCommandPools "create the command pools" * @todo move depth image, texture, texture samples, model stuff to renderers * -# @ref createCommandBuffers "create command buffers for swap chain image layout transitions" @@ -131,11 +131,16 @@ namespace gz::vlk { * @brief Register vulkan handles used by another object * @details * Use this function to register vulkan handles used by another object. - * When a @ref debugLog "validation message" contains one of these handles, the owner can + * When a @ref debugLog "validation message" contains one of these handles, the owner object can * be determined and added to the message. * This makes the debugging process easier when multiple objects use the same type of vulkan handle. + * + * This function is a ObjectsUsingVulkan factory and does not take an ObjectsUsingVulkan ptr. + * The reason is that this makes it easy to make the function a nop when not in debug mode (meaning `NDEBUG` is defined). + * The entire call (and therefore construction of the ObjectUsingVulkan object) can then be optimized away. */ - static void registerObjectUsingVulkan(const ObjectUsingVulkan& obj); + template + static void registerObjectUsingVulkan(std::string&& name, const T&&... pHandleConvertibles); /// @} /** @@ -209,37 +214,47 @@ namespace gz::vlk { */ void destroyCommandBuffers(std::vector& commandBuffers); - /** - * @brief Create a descriptor layout with bindings - */ - void createDescriptorSetLayout(std::vector bindings, vk::DescriptorSetLayout& layout); - /** * @brief Create a new graphics pipeline - * @param vertexShader Path to the SPIR-V vertex shader - * @param fragmentShader Path to the SPIR-V fragment shader - * @param useDepthStencil Wether to use depth // TODO - * @param renderPass The (already created) render pass - * @param pipelineLayout Pipeline layout handle to bind + * @params pipelineCI @ref create_pipeline_create_info "(Not necessary fully initalized)" create info struct. + * @param desciptorSetLayouts [Optional] Vector of descriptor set layouts + * @param useDepthStencil Wether to use depth * @param pipeline Pipeline handle to bind - * @param T the type of Vertex to use + * @param T the type of Vertex to use, either Vertex2D or Vertex3D * * @details - * Create a pipeline with: - * - 2 shader stages: vertex and fragment shader - * - 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::FrontFace::eCounterClockwise) + * @section create_pipeline_ci Pipeline Create Info + * @subsection create_pipeline_ci_optional Optional and default values + * The pipelineCI struct does not have to be fully initalized. + * Some values can be `nullptr`, in which case a default value is used to create the pipeline. + * The optional values and their defaults are: + * - pVertexInputState: initalized from `VertexT::getBindingDescription()` and `VertexT::getAttributeDescriptions()` + * - pViewportState: viewport of swap chain extent and scissor of swap chain extent + * - pRasterizationState: + * - fill polygons + * - backface culling + * - counter clockwise front face + * - pMultisampleState: one sample + * - pColorBlendState: one rgba color blend attachment with 1-alpha color blend factor + * - pDepthStencilState: compare less, depth test and write enabled (only used when useDepthStencil is true!) + * @subsection create_pipeline_ci_required Required values + * The following values have to be provided in pipelineCI. VkUserError is thrown when + * one of these is nullptr: + * - renderPass + * - pStages (and therefor stageCount, which is not checked) + * - subpass (creates no exception, since the default 0 might be the actual value!) + * + * @throws VkUserError when @ref create_pipeline_ci_required "required value" is not provided + * @throws VkException when pipeline (layout) creation fails + * + * @todo push constants, dynamicStates * - * @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, vk::RenderPass& renderPass, Pipeline& pipeline, vk::SpecializationInfo* fragSI=nullptr, vk::SpecializationInfo* vertSI=nullptr); + void createGraphicsPipeline(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline); vk::ShaderModule createShaderModule(const std::vector& code); + /* void createShaderStageCreateInfos(const std::vector>& shaders, std::vector& shaderStages); */ /** * @brief Allocate memory, create a buffer and bind buffer to memory @@ -287,7 +302,7 @@ namespace gz::vlk { 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 + * @brief Create as many framebuffers as images views, with the extent of the swap chain */ void createFramebuffers(std::vector& framebuffers, std::vector& imageViews, vk::RenderPass& renderPass, vk::ImageView depthImageView=VK_NULL_HANDLE); /** @@ -303,6 +318,14 @@ namespace gz::vlk { void destroyTextureSampler(vk::Sampler& sampler); + /** + * @brief Create a descriptor layout with bindings + */ + void createDescriptorSetLayout(const std::vector& bindings, vk::DescriptorSetLayout& layout); + void createDescriptorPool(const std::vector& poolSizes, uint32_t maxSets, vk::DescriptorPool& pool); + void createDescriptorSet(const vk::DescriptorSetLayout& layout, const vk::DescriptorPool& pool, vk::DescriptorSet& set); + void createDescriptorSets(const std::vector& layouts, const vk::DescriptorPool& pool, std::vector& sets); + /** * @name Public Interface: Image utility * @details @@ -598,8 +621,13 @@ namespace gz::vlk { */ vk::PresentModeKHR selectSwapChainPresentMode(const std::vector& availableModes); vk::Extent2D selectSwapExtent(const vk::SurfaceCapabilities2KHR& capabilities); + /** + * @brief Create swap chain, image views + */ void createSwapChain(); - void createSwapChainImageViews(); + /** + * @brief Destroy swap chain, image views + */ void cleanupSwapChain(); /** * @brief Recreate the swap chain for the current window size @@ -647,18 +675,6 @@ namespace gz::vlk { void createSyncObjects(); /// @} - - /** - * @name Shaders - */ - /// @{ - /** - * @brief Load a binary file into vector of bytes - * @todo Move to more generic constant, does not need to be member function - */ - static std::vector readFile(const std::string& filename); - /// @} - /** * @name Utility */ @@ -682,7 +698,7 @@ namespace gz::vlk { * @name Debugging: (handle ownership) */ /// @{ - static std::vector objectsUsingVulkan; + static std::vector> objectsUsingVulkan; /** * @brief Search for handles in message and get their owners * @details @@ -702,9 +718,14 @@ namespace gz::vlk { // // IMPLEMENTATIONS // - // +// PUBLIC INTERFACE: INIT AND CLEANUP + template + void VulkanInstance::registerObjectUsingVulkan(std::string&& name, const T&&... pHandleConvertibles) { + objectsUsingVulkan.emplace_back(std::unique_ptr(std::make_unique>(ObjectUsingVulkan(std::move(name), std::forward(pHandleConvertibles)...)))); + } + +// PUBLIC INTERFACE: CREATION AND DESTRUCTION // UNIFORM BUFFERS - // template void VulkanInstance::createUniformBuffers(std::vector& uniformBuffers, std::vector& uniformBuffersMemory) { vk::DeviceSize bufferSize = sizeof(T); @@ -717,9 +738,7 @@ namespace gz::vlk { } } - // - // UTILITY - // +// UTILITY template vk::Result VulkanInstance::runVkResultFunction(const char* name, Args&&... args) { auto f = reinterpret_cast(vkGetInstanceProcAddr(instance, name));