registerObjectUsingVulkan signature changed

registerObjectUsingVulkan is now a factory for ObjectUsingVulkan
This commit is contained in:
matthias@arch 2022-10-29 16:04:07 +02:00
parent 2169e3ee47
commit cdae3347a4
11 changed files with 643 additions and 469 deletions

View File

@ -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<vk::Image> renderImages;
std::vector<MemoryInfo> renderImageMemory;
std::vector<vk::ImageView> renderImageViews;
vk::Sampler imageSampler;
/// @}
std::vector<vk::CommandBuffer> commandBuffers;
/// On device local memory

View File

@ -9,6 +9,7 @@
#include <cstring>
#include <stdexcept>
#include <thread>
#include <vulkan/vulkan_enums.hpp>
namespace gz::vlk {
@ -35,9 +36,9 @@ namespace gz::vlk {
vk.createVertexBuffer<Vertex2D>(vertexCount, vertexBuffer, vertexBufferMemory, vertexBufferSize);
vk.createIndexBuffer<uint32_t>(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<vk::DescriptorSetLayout> descriptorSetLayouts = { textureManager.getDescriptorSetLayout() };
// specialization constant for sampler2D array length = atlas count
@ -71,23 +72,55 @@ namespace gz::vlk {
vk::SpecializationInfo specI;
specI.setData<uint32_t>(atlasCount);
specI.setMapEntries(specME);
vk.createGraphicsPipeline<Vertex2D>("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<vk::PipelineShaderStageCreateInfo> 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<Vertex3D>(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<vk::AttachmentDescription, 2> attachments = { colorBlendAttachment, depthAttachment }; */
std::vector<vk::AttachmentDescription2> attachments = { colorBlendAttachment };
std::vector<vk::SubpassDependency2> dependencies = { colorAttachmentSD, layoutTransitionSD };
std::vector<vk::SubpassDescription2> subpasses { drawSubpass, blitSubpass };
std::vector<vk::SubpassDependency2> 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<uint32_t>(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);

View File

@ -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<vk::Image> images;
std::vector<MemoryInfo> imageMemory;
std::vector<vk::ImageView> 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<vk::Framebuffer> framebuffers;
// PIPELINE
PipelineContainer pipelines;
PipelineContainer<Pipelines2D> pipelines;
// SWAPCHAIN RECREATION
/**

View File

@ -8,8 +8,11 @@
#include "vk_enum_string.h"
#include "vulkan_settings.hpp"
#include <gz-util/file_io.hpp>
#include <cstring>
#include <chrono>
#include <vulkan/vulkan_structs.hpp>
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<vk::DescriptorSetLayout> descriptorSetLayouts = { descriptorSetLayout };
vk.createGraphicsPipeline<Vertex3D>("shaders/vert.spv", "shaders/frag.spv", descriptorSetLayouts, true, renderPass, pipelines[PL_3D]);
createImageResources();
vk.createFramebuffers(framebuffers, renderImageViews, renderPass, depthImageView);
// VERTEX 3D PIPELINE
std::vector<vk::DescriptorSetLayout> 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<vk::PipelineShaderStageCreateInfo> 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<Vertex3D>(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<vk::PipelineShaderStageCreateInfo> 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<Vertex3D>(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<uint64_t>(static_cast<VkDescriptorPool>(descriptorPool)), "vs hpp:", reinterpret_cast<uint64_t>(&(*descriptorPool)));
// LAYOUTS
std::vector<vk::DescriptorSetLayoutBinding> 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<vk::DescriptorSetLayoutBinding> 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<vk::DescriptorSetLayoutBinding> bindings = { uboLayoutBinding, samplerLayoutBinding };
vk.createDescriptorSetLayout(bindings, descriptorSetLayout);
// POOL
std::array<vk::DescriptorPoolSize, 2> poolSizes;
poolSizes[0].type = vk::DescriptorType::eUniformBuffer;
poolSizes[0].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight());
poolSizes[1].type = vk::DescriptorType::eCombinedImageSampler;
poolSizes[1].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight());
vk::DescriptorPoolCreateInfo poolCI {
.maxSets = static_cast<uint32_t>(vk.getMaxFramesInFlight()),
std::vector<vk::DescriptorPoolSize> 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<vk::DescriptorSetLayout> layouts(vk.getMaxFramesInFlight(), descriptorSetLayout);
vk::DescriptorSetAllocateInfo setAI {
.descriptorPool = descriptorPool,
};
setAI.setSetLayouts(layouts);
// SET 1
std::vector<vk::DescriptorSetLayout> 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<vk::WriteDescriptorSet, 2> 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<vk::DescriptorSetLayout> 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<vk::DescriptorSet> 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<uint32_t>(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

View File

@ -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<vk::Image> images;
std::vector<MemoryInfo> imageMemory;
std::vector<vk::ImageView> 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<vk::Framebuffer> framebuffers;
// PIPELINE
PipelineContainer pipelines;
PipelineContainer<Pipelines3D> 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<vk::DescriptorSet> descriptorSets;
vk::DescriptorSetLayout uboDSL;
std::vector<vk::DescriptorSet> uboDS;
vk::DescriptorSetLayout sampleFromRenderImageDSL;
std::vector<vk::DescriptorSet> 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();
/**

View File

@ -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);
}

View File

@ -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<vk::DescriptorSetLayoutBinding> 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<vk::DescriptorSetLayoutBinding> 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<vk::DescriptorPoolSize> poolSizes {
vk::DescriptorPoolSize {
// 2) pool
vk::DescriptorPoolSize poolSize {
.type = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight())
.descriptorCount = vk.getMaxFramesInFlight(),
};
vk.createDescriptorPool({ poolSize }, vk.getMaxFramesInFlight(), descriptorPool);
// 3) Set
vk.createDescriptorSet(descriptorSetLayout, descriptorPool, descriptorSet);
// 4) configure sets
std::vector<vk::DescriptorImageInfo> 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<vk::DescriptorImageInfo> 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

View File

@ -58,14 +58,12 @@ namespace gz::vlk {
vk::DescriptorSet descriptorSet;
/* std::vector<vk::DescriptorSet> 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; */
/**

View File

@ -1,6 +1,6 @@
#pragma once
/* #include "vulkan_util.hpp" */
#include "vulkan_util.hpp"
#include <gz-util/log.hpp>
#include <initializer_list>

View File

@ -8,7 +8,10 @@
#include <gz-util/log.hpp>
#include <gz-util/util/regex.hpp>
#include <gz-util/util/string_conversion.hpp>
#include <memory>
#include <utility>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_enums.hpp>
#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<vk::DescriptorSetLayoutBinding> 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<VertexType VertexT>
void VulkanInstance::createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector<vk::DescriptorSetLayout>& 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<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline) {
// 1) sanity checks
if (pipelineCI.pStages == nullptr) {
throw VkUserError("pStages is nullptr", "VulkanInstance::createGraphicsPipeline");
}
if (static_cast<VkRenderPass>(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<vk::VertexInputAttributeDescription>
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<vk::DynamicState> dynamicStates = { */
/* vk::DynamicState::eViewport, */
@ -519,7 +499,8 @@ using std::uint32_t;
/* dynamicState.dynamicStateCount = static_cast<uint32_t>(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<pipeline>
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<Vertex2D>(const std::string& vertexShader, const std::string& fragmentShader, std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts, bool useDepthStencil, vk::RenderPass& renderPass, Pipeline& pipeline, vk::SpecializationInfo* fragSI, vk::SpecializationInfo* vertSI);
template void VulkanInstance::createGraphicsPipeline<Vertex3D>(const std::string& vertexShader, const std::string& fragmentShader, std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts, bool useDepthStencil, vk::RenderPass& renderPass, Pipeline& pipeline, vk::SpecializationInfo* fragSI, vk::SpecializationInfo* vertSI);
template void VulkanInstance::createGraphicsPipeline<Vertex2D>(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline);
template void VulkanInstance::createGraphicsPipeline<Vertex3D>(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline);
// SHADER MODULE
@ -587,6 +561,21 @@ using std::uint32_t;
return shaderModule;
}
/* void VulkanInstance::createShaderModules(const std::vector<std::pair<std::string, vk::SpecializationInfo*>>& shaders, std::vector<vk::PipelineShaderStageCreateInfo>& 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<uint32_t>* qFamiliesWithAccess) {
@ -674,7 +663,7 @@ using std::uint32_t;
// FRAMEBUFFERS
void VulkanInstance::createFramebuffers(std::vector<vk::Framebuffer>& framebuffers, std::vector<vk::ImageView>& 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<vk::DescriptorSetLayoutBinding>& 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<vk::DescriptorPoolSize>& 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<vk::DescriptorSetLayout>& layouts, const vk::DescriptorPool& pool, std::vector<vk::DescriptorSet>& 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<char> VulkanInstance::readFile(const std::string& filename) {
std::ifstream file(filename, std::ios::ate | std::ios::binary);
std::vector<char> 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<ObjectUsingVulkan> VulkanInstance::objectsUsingVulkan;
std::vector<std::unique_ptr<ObjectUsingVulkanBase>> 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;
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <memory>
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
/* #include <glm/glm.hpp> */
@ -14,8 +15,8 @@
#include "vertex.hpp"
#include "vulkan_util.hpp"
#include "vulkan_allocator.hpp"
#include "vulkan_allocator.hpp"
#include "vulkan_settings.hpp"
#include <gz-util/log.hpp>
@ -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<PtrToVulkanHppHandleConvertible... T>
static void registerObjectUsingVulkan(std::string&& name, const T&&... pHandleConvertibles);
/// @}
/**
@ -209,37 +214,47 @@ namespace gz::vlk {
*/
void destroyCommandBuffers(std::vector<vk::CommandBuffer>& commandBuffers);
/**
* @brief Create a descriptor layout with bindings
*/
void createDescriptorSetLayout(std::vector<vk::DescriptorSetLayoutBinding> 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<VertexType T>
void createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts, bool useDepthStencil, vk::RenderPass& renderPass, Pipeline& pipeline, vk::SpecializationInfo* fragSI=nullptr, vk::SpecializationInfo* vertSI=nullptr);
void createGraphicsPipeline(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline);
vk::ShaderModule createShaderModule(const std::vector<char>& code);
/* void createShaderStageCreateInfos(const std::vector<std::pair<std::string, vk::SpecializationInfo*>>& shaders, std::vector<vk::PipelineShaderStageCreateInfo>& shaderStages); */
/**
* @brief Allocate memory, create a buffer and bind buffer to memory
@ -287,7 +302,7 @@ namespace gz::vlk {
void createUniformBuffers(std::vector<vk::Buffer>& uniformBuffers, std::vector<MemoryInfo>& 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<vk::Framebuffer>& framebuffers, std::vector<vk::ImageView>& 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<vk::DescriptorSetLayoutBinding>& bindings, vk::DescriptorSetLayout& layout);
void createDescriptorPool(const std::vector<vk::DescriptorPoolSize>& 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<vk::DescriptorSetLayout>& layouts, const vk::DescriptorPool& pool, std::vector<vk::DescriptorSet>& sets);
/**
* @name Public Interface: Image utility
* @details
@ -598,8 +621,13 @@ namespace gz::vlk {
*/
vk::PresentModeKHR selectSwapChainPresentMode(const std::vector<vk::PresentModeKHR>& 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<char> readFile(const std::string& filename);
/// @}
/**
* @name Utility
*/
@ -682,7 +698,7 @@ namespace gz::vlk {
* @name Debugging: (handle ownership)
*/
/// @{
static std::vector<ObjectUsingVulkan> objectsUsingVulkan;
static std::vector<std::unique_ptr<ObjectUsingVulkanBase>> 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<PtrToVulkanHppHandleConvertible... T>
void VulkanInstance::registerObjectUsingVulkan(std::string&& name, const T&&... pHandleConvertibles) {
objectsUsingVulkan.emplace_back(std::unique_ptr<ObjectUsingVulkanBase>(std::make_unique<ObjectUsingVulkan<T...>>(ObjectUsingVulkan(std::move(name), std::forward<const T>(pHandleConvertibles)...))));
}
// PUBLIC INTERFACE: CREATION AND DESTRUCTION
// UNIFORM BUFFERS
//
template<typename T>
void VulkanInstance::createUniformBuffers(std::vector<vk::Buffer>& uniformBuffers, std::vector<MemoryInfo>& uniformBuffersMemory) {
vk::DeviceSize bufferSize = sizeof(T);
@ -717,9 +738,7 @@ namespace gz::vlk {
}
}
//
// UTILITY
//
// UTILITY
template<typename T, typename... Args>
vk::Result VulkanInstance::runVkResultFunction(const char* name, Args&&... args) {
auto f = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name));