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_(); void cleanup_();
VulkanInstance& vk; VulkanInstance& vk;
TextureManager& textureManager; 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; std::vector<vk::CommandBuffer> commandBuffers;
/// On device local memory /// On device local memory

View File

@ -9,6 +9,7 @@
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
#include <thread> #include <thread>
#include <vulkan/vulkan_enums.hpp>
namespace gz::vlk { namespace gz::vlk {
@ -35,9 +36,9 @@ namespace gz::vlk {
vk.createVertexBuffer<Vertex2D>(vertexCount, vertexBuffer, vertexBufferMemory, vertexBufferSize); vk.createVertexBuffer<Vertex2D>(vertexCount, vertexBuffer, vertexBufferMemory, vertexBufferSize);
vk.createIndexBuffer<uint32_t>(indexCount, indexBuffer, indexBufferMemory, indexBufferSize); vk.createIndexBuffer<uint32_t>(indexCount, indexBuffer, indexBufferMemory, indexBufferSize);
initSwapChainDependantResources(); initSwapChainDependantResources();
VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan("Renderer2D", VulkanInstance::registerObjectUsingVulkan("Renderer2D",
{ &pipelines[PL_2D].pipeline, &renderPass, &vertexBuffer, &vertexBufferMemory, &indexBuffer, &indexBufferMemory }, &pipelines[R2Render].pipeline, &renderPass, &vertexBuffer, &vertexBufferMemory.memory, &indexBuffer, &indexBufferMemory.memory,
{ &framebuffers, &images, &imageMemory, &imageViews, &commandBuffers })); &framebuffers, &renderImages, &renderImageViews, &commandBuffers); // &renderImageMemory,
rLog("Created Renderer2D"); rLog("Created Renderer2D");
} }
@ -57,8 +58,8 @@ namespace gz::vlk {
// //
void Renderer2D::initSwapChainDependantResources() { void Renderer2D::initSwapChainDependantResources() {
createRenderPass(); createRenderPass();
createImages(); createImageResources();
vk.createFramebuffers(framebuffers, imageViews, renderPass); vk.createFramebuffers(framebuffers, renderImageViews, renderPass);
std::vector<vk::DescriptorSetLayout> descriptorSetLayouts = { textureManager.getDescriptorSetLayout() }; std::vector<vk::DescriptorSetLayout> descriptorSetLayouts = { textureManager.getDescriptorSetLayout() };
// specialization constant for sampler2D array length = atlas count // specialization constant for sampler2D array length = atlas count
@ -71,23 +72,55 @@ namespace gz::vlk {
vk::SpecializationInfo specI; vk::SpecializationInfo specI;
specI.setData<uint32_t>(atlasCount); specI.setData<uint32_t>(atlasCount);
specI.setMapEntries(specME); 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() { void Renderer2D::cleanupSwapChainDependantResources() {
// destroy pipelines // destroy pipelines
pipelines.destroy(vk.getDevice()); pipelines.clear(vk.getDevice());
vk.destroyFramebuffers(framebuffers); vk.destroyFramebuffers(framebuffers);
for (size_t i = 0; i < images.size(); i++) { #ifndef RENDERER_2D_RENDER_TO_SWAP_CHAIN
vk.destroyImageView(imageViews[i]); for (size_t i = 0; i < renderImages.size(); i++) {
vk.destroyImage(images[i], imageMemory[i]); vk.destroyImageView(renderImageViews[i]);
vk.destroyImage(renderImages[i], renderImageMemory[i]);
} }
#endif
vk.getDevice().destroyRenderPass(renderPass, nullptr); vk.getDevice().destroyRenderPass(renderPass, nullptr);
} }
@ -100,15 +133,24 @@ namespace gz::vlk {
// //
// IMAGES // IMAGES
// //
void Renderer2D::createImages() { void Renderer2D::createImageResources() {
images.resize(vk.getScImages().size()); renderImageViews.resize(vk.getScImages().size());
imageMemory.resize(vk.getScImages().size()); #ifndef RENDERER_2D_RENDER_TO_SWAP_CHAIN
imageViews.resize(vk.getScImages().size()); renderImages.resize(vk.getScImages().size());
renderImageMemory.resize(vk.getScImages().size());
vk::ImageUsageFlags usage= vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc; vk::ImageUsageFlags usage= vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc;
for (size_t i = 0; i < images.size(); i++) { 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, images[i], imageMemory[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(), images[i], imageViews[i], vk::ImageAspectFlagBits::eColor); 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.attachment = 1; */
/* depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; */ /* depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; */
vk::SubpassDescription2 subpass { // SUBPASS 1: DRAW STUFF
vk::SubpassDescription2 drawSubpass {
.pipelineBindPoint = vk::PipelineBindPoint::eGraphics, .pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
.colorAttachmentCount = 1, .colorAttachmentCount = 1,
.pColorAttachments = &colorAttachmentRef, .pColorAttachments = &colorAttachmentRef,
/* .pDepthStencilAttachment = &depthAttachmentRef, */ /* .pDepthStencilAttachment = &depthAttachmentRef, */
}; };
vk::SubpassDependency2 colorAttachmentSD { vk::SubpassDependency2 dsColorAttachmentSD {
.srcSubpass = VK_SUBPASS_EXTERNAL, .srcSubpass = VK_SUBPASS_EXTERNAL,
.dstSubpass = 0, .dstSubpass = 0,
.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
@ -162,37 +205,46 @@ namespace gz::vlk {
}; };
// dependecy for the image layout transition to transfer dst // dependecy for the image layout transition to transfer dst
vk::SubpassDependency2 layoutTransitionSD { /* vk::SubpassDependency2 dsLayoutTransitionSD { */
.srcSubpass = 0, /* .srcSubpass = 0, */
.dstSubpass = VK_SUBPASS_EXTERNAL, /* .dstSubpass = 1, */
.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, /* .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput, */
.dstStageMask = vk::PipelineStageFlagBits::eTransfer, /* .dstStageMask = vk::PipelineStageFlagBits::eTransfer, */
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, /* .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite, */
.dstAccessMask = vk::AccessFlagBits::eTransferRead, /* .dstAccessMask = vk::AccessFlagBits::eTransferRead, */
.dependencyFlags = vk::DependencyFlagBits::eByRegion, /* .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::array<vk::AttachmentDescription, 2> attachments = { colorBlendAttachment, depthAttachment }; */
std::vector<vk::AttachmentDescription2> attachments = { colorBlendAttachment }; 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; vk::RenderPassCreateInfo2 renderPassCI;
renderPassCI.setDependencies(dependencies);
renderPassCI.setAttachments(attachments); renderPassCI.setAttachments(attachments);
renderPassCI.setSubpasses(subpass); renderPassCI.setSubpasses(subpasses);
renderPassCI.setDependencies(dependencies);
vk::Result result = vk.getDevice().createRenderPass2(&renderPassCI, nullptr, &renderPass); vk::Result result = vk.getDevice().createRenderPass2(&renderPassCI, nullptr, &renderPass);
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
throw getVkException(result, "Could not create render pass", "Renderer2D::createRenderPass"); throw getVkException(result, "Could not create render pass", "Renderer2D::createRenderPass");
} }
rLog("createRenderPass: Created render pass."); rLog("createRenderPass: Created render pass.");
} }
@ -224,7 +276,7 @@ namespace gz::vlk {
commandBuffers[currentFrame].beginRenderPass(&renderPassBI, vk::SubpassContents::eInline); 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::Buffer vertexBuffers[] = { vertexBuffer };
vk::DeviceSize offsets[] = {0}; vk::DeviceSize offsets[] = {0};
uint32_t bindingCount = 1; uint32_t bindingCount = 1;
@ -237,7 +289,7 @@ namespace gz::vlk {
uint32_t firstSet = 0; uint32_t firstSet = 0;
uint32_t dynamicOffsetCount = 0; uint32_t dynamicOffsetCount = 0;
uint32_t* dynamicOffsets = nullptr; 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 instanceCount = 1;
int firstIndex = 0; 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].drawIndexed(static_cast<uint32_t>(shapesIndicesCount), instanceCount, firstIndex, NO_OFFSET, firstInstance);
commandBuffers[currentFrame].endRenderPass(); 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(); result = commandBuffers[currentFrame].end();
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
rLog.error("Failed to record 2D - command buffer", "VkResult:", result); rLog.error("Failed to record 2D - command buffer", "VkResult:", result);

View File

@ -7,6 +7,10 @@
#include "vulkan_util.hpp" #include "vulkan_util.hpp"
namespace gz::vlk { namespace gz::vlk {
enum Pipelines2D {
R2Render,
};
class Renderer2D : public Renderer { class Renderer2D : public Renderer {
public: public:
/** /**
@ -60,20 +64,21 @@ namespace gz::vlk {
*/ */
void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame); void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame);
// IMAGE
/** /**
* @name Image (render targets) * @brief Create the render image resources
* @details * @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; void createImageResources();
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();
/// @} /// @}
/** /**
@ -95,9 +100,13 @@ namespace gz::vlk {
vk::RenderPass renderPass; vk::RenderPass renderPass;
/// @} /// @}
/**
* @brief Framebuffer for renderImageViews
*/
std::vector<vk::Framebuffer> framebuffers; std::vector<vk::Framebuffer> framebuffers;
// PIPELINE // PIPELINE
PipelineContainer pipelines; PipelineContainer<Pipelines2D> pipelines;
// SWAPCHAIN RECREATION // SWAPCHAIN RECREATION
/** /**

View File

@ -8,8 +8,11 @@
#include "vk_enum_string.h" #include "vk_enum_string.h"
#include "vulkan_settings.hpp" #include "vulkan_settings.hpp"
#include <gz-util/file_io.hpp>
#include <cstring> #include <cstring>
#include <chrono> #include <chrono>
#include <vulkan/vulkan_structs.hpp>
namespace gz::vlk { namespace gz::vlk {
// //
@ -41,11 +44,12 @@ namespace gz::vlk {
createUniformBuffers(); createUniformBuffers();
createDescriptorResources(); createDescriptorResources();
initSwapChainDependantResources(); initSwapChainDependantResources();
VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan("Renderer3D", VulkanInstance::registerObjectUsingVulkan("Renderer3D",
{ &pipelines[PL_3D].pipeline, &renderPass, &vertexBuffer, &vertexBufferMemory, &indexBuffer, &indexBufferMemory, &renderPass, &imageSampler, &vertexBuffer, &vertexBufferMemory.memory, &indexBuffer, &indexBufferMemory.memory,
&descriptorSetLayout, &descriptorPool, }, &pipelines[R3Render].pipeline, //&pipelines[blendToSC].pipeline,
{ &framebuffers, &images, &imageMemory, &imageViews, &commandBuffers, &descriptorPool, &uboDSL, &sampleFromRenderImageDSL,
&descriptorSets })); &framebuffers, &renderImages, &renderImageViews, &commandBuffers,
&uboDS, &sampleFromRenderImageDS); // missing: &renderImageMemory,
rLog.log1("Created Renderer3D"); rLog.log1("Created Renderer3D");
} }
@ -55,7 +59,7 @@ namespace gz::vlk {
for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) { for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) {
vk.destroyBuffer(uniformBuffers[i], uniformBuffersMemory[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); vk.getDevice().destroyDescriptorPool(descriptorPool, NO_ALLOC);
cleanupSwapChainDependantResources(); cleanupSwapChainDependantResources();
@ -69,27 +73,84 @@ namespace gz::vlk {
void Renderer3D::initSwapChainDependantResources() { void Renderer3D::initSwapChainDependantResources() {
// UPDATE DOC ON CHANGES! // UPDATE DOC ON CHANGES!
createRenderPass(); createRenderPass();
createImages();
createDepthImage(); createDepthImage();
vk.createFramebuffers(framebuffers, imageViews, renderPass, depthImageView); createImageResources();
std::vector<vk::DescriptorSetLayout> descriptorSetLayouts = { descriptorSetLayout }; vk.createFramebuffers(framebuffers, renderImageViews, renderPass, depthImageView);
vk.createGraphicsPipeline<Vertex3D>("shaders/vert.spv", "shaders/frag.spv", descriptorSetLayouts, true, renderPass, pipelines[PL_3D]);
// 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() { void Renderer3D::cleanupSwapChainDependantResources() {
// destroy pipelines // destroy pipelines
pipelines.destroy(vk.getDevice()); pipelines.clear(vk.getDevice());
vk.destroyFramebuffers(framebuffers); vk.destroyFramebuffers(framebuffers);
vk.destroyImageView(depthImageView); vk.destroyImageView(depthImageView);
vk.destroyImage(depthImage, depthImageMemory); vk.destroyImage(depthImage, depthImageMemory);
for (size_t i = 0; i < images.size(); i++) { #ifndef RENDERER_3D_RENDER_TO_SWAP_CHAIN
vk.destroyImageView(imageViews[i]); for (size_t i = 0; i < renderImages.size(); i++) {
vk.destroyImage(images[i], imageMemory[i]); vk.destroyImageView(renderImageViews[i]);
vk.destroyImage(renderImages[i], renderImageMemory[i]);
} }
#endif
vk.getDevice().destroyRenderPass(renderPass, nullptr); vk.getDevice().destroyRenderPass(renderPass, nullptr);
} }
@ -103,15 +164,24 @@ namespace gz::vlk {
// //
// IMAGES // IMAGES
// //
void Renderer3D::createImages() { void Renderer3D::createImageResources() {
images.resize(vk.getScImages().size()); renderImageViews.resize(vk.getScImages().size());
imageMemory.resize(vk.getScImages().size()); #ifndef RENDERER_3D_RENDER_TO_SWAP_CHAIN
imageViews.resize(vk.getScImages().size()); renderImages.resize(vk.getScImages().size());
renderImageMemory.resize(vk.getScImages().size());
vk::ImageUsageFlags usage= vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc; vk::ImageUsageFlags usage= vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc;
for (size_t i = 0; i < images.size(); i++) { 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, images[i], imageMemory[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(), images[i], imageViews[i], vk::ImageAspectFlagBits::eColor); 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 // DESCRIPTORS
// //
void Renderer3D::createDescriptorResources() { void Renderer3D::createDescriptorResources() {
// LAYOUT rLog("createDescriptorResources: pool", reinterpret_cast<uint64_t>(static_cast<VkDescriptorPool>(descriptorPool)), "vs hpp:", reinterpret_cast<uint64_t>(&(*descriptorPool)));
// 1) uniform buffer object // LAYOUTS
vk::DescriptorSetLayoutBinding uboLayoutBinding { std::vector<vk::DescriptorSetLayoutBinding> uboDSLB;
// SET 1: uniform buffer object
uboDSLB.emplace_back(vk::DescriptorSetLayoutBinding {
.binding = 0, .binding = 0,
.descriptorType = vk::DescriptorType::eUniformBuffer, .descriptorType = vk::DescriptorType::eUniformBuffer,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eVertex, .stageFlags = vk::ShaderStageFlagBits::eVertex,
/* .pImmutableSamplers = nullptr, */ /* .pImmutableSamplers = nullptr, */
}; });
// 2) combined image sampler /* // SET 1: combined image sampler */
vk::DescriptorSetLayoutBinding samplerLayoutBinding { /* set1bindings.emplace_back(vk::DescriptorSetLayoutBinding { */
.binding = 1, /* .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, .descriptorType = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eFragment, .stageFlags = vk::ShaderStageFlagBits::eFragment,
/* .pImmutableSamplers = nullptr, */ });
}; vk.createDescriptorSetLayout(sampleFromRenderImageDSLB, sampleFromRenderImageDSL);
#endif
std::vector<vk::DescriptorSetLayoutBinding> bindings = { uboLayoutBinding, samplerLayoutBinding };
vk.createDescriptorSetLayout(bindings, descriptorSetLayout);
// POOL // POOL
std::array<vk::DescriptorPoolSize, 2> poolSizes; std::vector<vk::DescriptorPoolSize> poolSizes;
poolSizes[0].type = vk::DescriptorType::eUniformBuffer; poolSizes = {
poolSizes[0].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight()); { .type = vk::DescriptorType::eUniformBuffer, .descriptorCount = vk.getMaxFramesInFlight() },
poolSizes[1].type = vk::DescriptorType::eCombinedImageSampler; #ifndef RENDERER_3D_RENDER_TO_SWAP_CHAIN
poolSizes[1].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight()); { .type = vk::DescriptorType::eCombinedImageSampler, .descriptorCount = vk.getMaxFramesInFlight() },
#endif
vk::DescriptorPoolCreateInfo poolCI {
.maxSets = static_cast<uint32_t>(vk.getMaxFramesInFlight()),
}; };
poolCI.setPoolSizes(poolSizes); vk.createDescriptorPool(poolSizes, vk.getMaxFramesInFlight(), descriptorPool);
vk::Result result;
std::tie(result, descriptorPool) = vk.getDevice().createDescriptorPool(poolCI);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to create descriptor pool", "Renderer3D::createDescriptorResources");
}
// SETS // SETS
std::vector<vk::DescriptorSetLayout> layouts(vk.getMaxFramesInFlight(), descriptorSetLayout); // SET 1
vk::DescriptorSetAllocateInfo setAI { std::vector<vk::DescriptorSetLayout> layouts1(vk.getMaxFramesInFlight(), uboDSL);
.descriptorPool = descriptorPool, vk.createDescriptorSets(layouts1, descriptorPool, uboDS);
};
setAI.setSetLayouts(layouts);
// 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++) { for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) {
vk::DescriptorBufferInfo bufferI { vk::DescriptorBufferInfo bufferI {
.buffer = uniformBuffers[i], .buffer = uniformBuffers[i],
@ -294,32 +359,46 @@ namespace gz::vlk {
.range = VK_WHOLE_SIZE, // sizeof(UniformBufferObject), .range = VK_WHOLE_SIZE, // sizeof(UniformBufferObject),
}; };
vk::DescriptorImageInfo imageI { vk::WriteDescriptorSet descriptorW{
.sampler = textureManager.getTextureAtlas().getTextureSampler(), .dstSet = uboDS[i],
.imageView = textureManager.getTextureAtlas().getTextureImageView(), .dstBinding = 0,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .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[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 // write 1, copy 0
vk.getDevice().updateDescriptorSets(descriptorW, nullptr); vk.getDevice().updateDescriptorSets(descriptorW, nullptr);
} } // for
rLog.log0("createDescriptorResources: Created descriptor layouts, pool and sets."); 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].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::Buffer vertexBuffers[] = { vertexBuffer };
vk::DeviceSize offsets[] = {0}; vk::DeviceSize offsets[] = {0};
uint32_t bindingCount = 1; uint32_t bindingCount = 1;
@ -407,15 +486,21 @@ namespace gz::vlk {
commandBuffers[currentFrame].bindIndexBuffer(indexBuffer, NO_OFFSET, vk::IndexType::eUint32); commandBuffers[currentFrame].bindIndexBuffer(indexBuffer, NO_OFFSET, vk::IndexType::eUint32);
uint32_t firstSet = 0; 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 instanceCount = 1;
int firstIndex = 0; int firstIndex = 0;
int firstInstance = 0; int firstInstance = 0;
commandBuffers[currentFrame].drawIndexed(static_cast<uint32_t>(model.indices.size()), instanceCount, firstIndex, NO_OFFSET, firstInstance); 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(); 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(); result = commandBuffers[currentFrame].end();
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
rLog.error("Failed to record 3D - command buffer", "VkResult:", result); rLog.error("Failed to record 3D - command buffer", "VkResult:", result);
@ -470,9 +555,4 @@ namespace gz::vlk {
vk.getDevice().unmapMemory(uniformBufferMI.memory); vk.getDevice().unmapMemory(uniformBufferMI.memory);
} }
} // namespace gz::vlk } // namespace gz::vlk

View File

@ -12,6 +12,10 @@ namespace gz::vlk {
alignas(16) glm::mat4 projection; alignas(16) glm::mat4 projection;
}; };
enum Pipelines3D {
R3Render,
};
class Renderer3D : public Renderer { class Renderer3D : public Renderer {
public: public:
/** /**
@ -40,22 +44,24 @@ namespace gz::vlk {
void updateUniformBuffer(); void updateUniformBuffer();
/** /**
* @name Image (render targets) * @brief Create the render image resources
* @details * @details
* The images are used as render targets. After rendering, the current image gets blitted onto the current swap chain image. * If `RENDERER_3D_RENDER_TO_SWAP_CHAIN`:
*/ * - renderImages are null handles
/// @{ * - renderImageMemory are null handles
std::vector<vk::Image> images; * - renderImageViews are views to VulkanInstance::getScImages()
std::vector<MemoryInfo> imageMemory; * - renderImageSampler is null handle
std::vector<vk::ImageView> imageViews; *
/** * Else:
* @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images * - renderImages are images on renderImageMemory
*/ * - renderImageViews are views to renderImages
void createImages(); * - renderImageSampler is a combined image sampler
/// @}
/**
* @name Depth
*/ */
void createImageResources();
/**
* @name Depth
*/
/// @{ /// @{
vk::Image depthImage; vk::Image depthImage;
MemoryInfo depthImageMemory; MemoryInfo depthImageMemory;
@ -66,17 +72,33 @@ namespace gz::vlk {
void createDepthImage(); void createDepthImage();
/// @} /// @}
/** /**
* @name Render pass * @name Render pass
* @details * @details
* Attachments: * @section r3p_rp Render pass
* - color blend: * @subsection r3p_subpass1 Subpass 1: Rendering
* - loadOp = vk::AttachmentLoadOp::eClear * Attributes:
* - storeOp = vk::AttachmentStoreOp::eStore * - Pipeline: `Pipelines3D::R3Render`
* - initialLayout = vk::ImageLayout::eColorAttachmentOptimal * - Descriptor layouts: `@ref r3p_desc1 "descriptorSet1Layout"` and `@ref tm_desc "TextureManager::descriptorSetLayout"`
* - finalLayout = vk::ImageLayout::eColorAttachmentOptimal * - Attachments:
* - stencil load/store = dont care * - 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 * @brief Create a render pass
@ -87,39 +109,37 @@ namespace gz::vlk {
std::vector<vk::Framebuffer> framebuffers; std::vector<vk::Framebuffer> framebuffers;
// PIPELINE // PIPELINE
PipelineContainer pipelines; PipelineContainer<Pipelines3D> pipelines;
/** /**
* @name Desciptors * @name Desciptors
* @details These functions create a desciptor with bindings for * @details
* -# UniformBufferObject (DESCRIPTOR_TYPE_UNIFORM_BUFFER) *
* -# Combined Image Sampler (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) * @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::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 * @brief Create @ref r3d_desc "all descritptor resources"
* @details Create a desciptor set layout with bindings for
* -# UniformBufferObject (DESCRIPTOR_TYPE_UNIFORM_BUFFER)
* -# Combined Image Sampler (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
*/ */
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(); void createDescriptorResources();
/// @}
/** /**
* @brief Swapchain recreation * @name Swapchain recreation
*/ */
/// @{ /// @{
/** /**
* @brief Cleans up resources that were initialized by initSwapChainDependantResources * @brief Cleans up resources that were initialized by initSwapChainDependantResources
@ -133,7 +153,8 @@ namespace gz::vlk {
* - @ref createImages() "images and imageViews" * - @ref createImages() "images and imageViews"
* - @ref createDepthImage() "depth image and view" * - @ref createDepthImage() "depth image and view"
* - @ref VulkanInstance::createFramebuffers() "framebuffers" * - @ref VulkanInstance::createFramebuffers() "framebuffers"
* - pipeline * - pipelines:
* - R3Render
*/ */
void initSwapChainDependantResources(); void initSwapChainDependantResources();
/** /**

View File

@ -43,9 +43,8 @@ TextureAtlas::TextureAtlas(VulkanInstance& instance, uint16_t slotWidth, uint16_
freeAreas.insert({ 0, 0, slotCountX, slotCountY}); freeAreas.insert({ 0, 0, slotCountX, slotCountY});
createImageResources(); createImageResources();
/* vk.registerCleanupCallback(std::bind(&TextureAtlas::cleanup, this)); */ /* vk.registerCleanupCallback(std::bind(&TextureAtlas::cleanup, this)); */
VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan(std::string("TextureAtlas-") + gz::toString(slotWidth) + "x" + gz::toString(slotHeight), VulkanInstance::registerObjectUsingVulkan(std::string("TextureAtlas-") + gz::toString(slotWidth) + "x" + gz::toString(slotHeight),
{ &textureImage, &textureImageMemory, &textureImageView, &textureSampler }, &textureImage, &textureImageMemory.memory, &textureImageView, &textureSampler);
{}));
} }

View File

@ -19,12 +19,9 @@ namespace gz::vlk {
vk.registerCleanupCallback(std::bind(&TextureManager::cleanup, this)); vk.registerCleanupCallback(std::bind(&TextureManager::cleanup, this));
atlases.emplace_back(TextureAtlas(vk, 24, 24, 24, 24)); atlases.emplace_back(TextureAtlas(vk, 24, 24, 24, 24));
createDescriptorSetLayout(); createDescriptorResources();
createDescriptorPool(); VulkanInstance::registerObjectUsingVulkan("TextureManager",
createDescriptorSet(); &descriptorSetLayout, &descriptorPool, &descriptorSet);
VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan("TextureManager",
{ &descriptorSetLayout, &descriptorPool, &descriptorSet },
{}));
} }
@ -69,79 +66,50 @@ namespace gz::vlk {
// //
// DESCRIPTOR SET // DESCRIPTOR SET
// //
void TextureManager::createDescriptorSetLayout() { void TextureManager::createDescriptorResources() {
// combined image sampler // 1) layout
std::vector<vk::DescriptorSetLayoutBinding> samplerLayoutBindings(atlases.size(), { // combined image sampler
.binding = 0, std::vector<vk::DescriptorSetLayoutBinding> samplerLayoutBindings(atlases.size(), {
.descriptorType = vk::DescriptorType::eCombinedImageSampler, .binding = 0,
.descriptorCount = 1, .descriptorType = vk::DescriptorType::eCombinedImageSampler,
.stageFlags = vk::ShaderStageFlagBits::eFragment, .descriptorCount = 1,
/* .pImmutableSamplers = nullptr, */ .stageFlags = vk::ShaderStageFlagBits::eFragment,
} /* .pImmutableSamplers = nullptr, */
); }
);
vk.createDescriptorSetLayout(samplerLayoutBindings, descriptorSetLayout);
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCI; // 2) pool
descriptorSetLayoutCI.setBindings(samplerLayoutBindings); vk::DescriptorPoolSize poolSize {
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 {
.type = vk::DescriptorType::eCombinedImageSampler, .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 }; vk::WriteDescriptorSet descriptorW {
poolCI.setPoolSizes(poolSizes); .dstSet = descriptorSet,
.dstBinding = 0,
vk::Result result; .dstArrayElement = 0,
std::tie(result, descriptorPool) = vk.getDevice().createDescriptorPool(poolCI); .descriptorCount = 1,
if (result != vk::Result::eSuccess) { .descriptorType = vk::DescriptorType::eCombinedImageSampler,
throw getVkException(result, "Failed to create descriptor pool", "TextureManager::createDescriptorPool"); };
} descriptorW.setImageInfo(imageInfos);
/* vLog("createDescriptorPool: Created descriptor pool."); */
} // 1 write, no copies
vk.getDevice().updateDescriptorSets(descriptorW, nullptr);
tLog.log0("createDescriptorSets: Created descriptor sets.");
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");
} }
// 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 } // namespace gz::vlk

View File

@ -58,14 +58,12 @@ namespace gz::vlk {
vk::DescriptorSet descriptorSet; vk::DescriptorSet descriptorSet;
/* std::vector<vk::DescriptorSet> descriptorSets; */ /* std::vector<vk::DescriptorSet> descriptorSets; */
/** /**
* @brief Create a descriptor set layout * @brief Create a descriptor set, layout and pool
* @details * @details
* Bindings: * Bindings:
* -0 COMBINED_IMAGE_SAMPLER * -0. texture sampler array COMBINED_IMAGE_SAMPLER[atlasCount]
*/ */
void createDescriptorSetLayout(); void createDescriptorResources();
void createDescriptorPool();
void createDescriptorSet();
/* const uint32_t bindingCombinedImageSampler = 1; */ /* const uint32_t bindingCombinedImageSampler = 1; */
/** /**

View File

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

View File

@ -8,7 +8,10 @@
#include <gz-util/log.hpp> #include <gz-util/log.hpp>
#include <gz-util/util/regex.hpp> #include <gz-util/util/regex.hpp>
#include <gz-util/util/string_conversion.hpp> #include <gz-util/util/string_conversion.hpp>
#include <memory>
#include <utility> #include <utility>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_enums.hpp>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h" #include "stb_image.h"
@ -59,9 +62,10 @@ using std::uint32_t;
if (glfwVulkanSupported() == GLFW_FALSE) { if (glfwVulkanSupported() == GLFW_FALSE) {
throw std::runtime_error("Vulkan not supported."); throw std::runtime_error("Vulkan not supported.");
} }
VulkanInstance::registerObjectUsingVulkan(ObjectUsingVulkan("VulkanInstance",
{ &instance, &physicalDevice, &device, &graphicsQ, &presentQ, &transferQ, &commandPoolGraphics, &commandPoolTransfer, &surface, &swapChain }, VulkanInstance::registerObjectUsingVulkan("VulkanInstance",
{ &scImages, &scImageViews, &commandBuffersBegin, &commandBuffersEnd })); &instance, &physicalDevice, &device, &graphicsQ, &presentQ, &transferQ, &commandPoolGraphics, &commandPoolTransfer, &surface, &swapChain,
&scImages, &scImageViews, &commandBuffersBegin, &commandBuffersEnd);
createInstance(); createInstance();
setupDebugMessenger(); setupDebugMessenger();
createSurface(); createSurface();
@ -71,7 +75,6 @@ using std::uint32_t;
createLogicalDevice(); createLogicalDevice();
createSwapChain(); createSwapChain();
createSwapChainImageViews();
createCommandPools(); createCommandPools();
createCommandBuffers(commandBuffersBegin); createCommandBuffers(commandBuffersBegin);
@ -81,7 +84,7 @@ using std::uint32_t;
/* createDescriptorSets(); // after UniformBuffers */ /* createDescriptorSets(); // after UniformBuffers */
for (auto& obj : VulkanInstance::objectsUsingVulkan) { for (auto& obj : VulkanInstance::objectsUsingVulkan) {
obj.updateHandles(); obj->updateHandles();
} }
} }
@ -165,8 +168,10 @@ using std::uint32_t;
// transition to transfer dst layout // transition to transfer dst layout
transitionImageLayout(scImages[imageIndex], scImageFormat, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, &commandBuffersBegin[currentFrame]); transitionImageLayout(scImages[imageIndex], scImageFormat, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, &commandBuffersBegin[currentFrame]);
vk::ImageMemoryBarrier2 imageBarrier { vk::ImageMemoryBarrier2 imageBarrier {
.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe, .srcStageMask = vk::PipelineStageFlagBits2::eNone,
.srcAccessMask = vk::AccessFlagBits2::eNone,
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer, .dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
.oldLayout = vk::ImageLayout::eUndefined, .oldLayout = vk::ImageLayout::eUndefined,
.newLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eTransferDstOptimal,
.image = scImages[imageIndex], .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 // PUBLIC INTERFACE: VARIOUS UTILITY
@ -395,45 +395,19 @@ using std::uint32_t;
commandBuffers.resize(0); 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 // GRAPHICS PIPELINE
template<VertexType VertexT> 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) { void VulkanInstance::createGraphicsPipeline(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline) {
auto vertShaderCode = readFile(vertexShader); // 1) sanity checks
auto fragShaderCode = readFile(fragmentShader); if (pipelineCI.pStages == nullptr) {
throw VkUserError("pStages is nullptr", "VulkanInstance::createGraphicsPipeline");
vk::ShaderModule vertShaderModule = createShaderModule(vertShaderCode); }
vk::ShaderModule fragShaderModule = createShaderModule(fragShaderCode); if (static_cast<VkRenderPass>(pipelineCI.renderPass) == VK_NULL_HANDLE) {
throw VkUserError("renderPass is VK_NULL_HANDLE", "VulkanInstance::createGraphicsPipeline");
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 };
// 2) construct default create infos
// default vertexInputStateCI
vk::VertexInputBindingDescription bindingD = VertexT::getBindingDescription(); vk::VertexInputBindingDescription bindingD = VertexT::getBindingDescription();
// array<vk::VertexInputAttributeDescription> // array<vk::VertexInputAttributeDescription>
auto attributeD = VertexT::getAttributeDescriptions(); auto attributeD = VertexT::getAttributeDescriptions();
@ -442,11 +416,13 @@ using std::uint32_t;
vertexInputStateCI.setVertexAttributeDescriptions(attributeD); vertexInputStateCI.setVertexAttributeDescriptions(attributeD);
vertexInputStateCI.setVertexBindingDescriptions(bindingD); vertexInputStateCI.setVertexBindingDescriptions(bindingD);
// default inputAssemblyStateCI
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCI { vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCI {
.topology = vk::PrimitiveTopology::eTriangleList, .topology = vk::PrimitiveTopology::eTriangleList,
.primitiveRestartEnable = VK_FALSE, .primitiveRestartEnable = VK_FALSE,
}; };
// default viewportState
vk::Viewport viewport { vk::Viewport viewport {
.x = 0.0f, .x = 0.0f,
.y = 0.0f, .y = 0.0f,
@ -457,7 +433,7 @@ using std::uint32_t;
}; };
vk::Rect2D scissor { vk::Rect2D scissor {
.offset = {0, 0}, .offset = { 0, 0 },
.extent = scExtent, .extent = scExtent,
}; };
@ -468,7 +444,8 @@ using std::uint32_t;
.pScissors = &scissor, .pScissors = &scissor,
}; };
vk::PipelineRasterizationStateCreateInfo rasterizerCI { // default rasterizationState
vk::PipelineRasterizationStateCreateInfo rasterizationStateCI {
.depthClampEnable = VK_FALSE, .depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE, .rasterizerDiscardEnable = VK_FALSE,
.polygonMode = vk::PolygonMode::eFill, .polygonMode = vk::PolygonMode::eFill,
@ -482,6 +459,7 @@ using std::uint32_t;
/* .depthBiasSlopeFactor = 0.0f, */ /* .depthBiasSlopeFactor = 0.0f, */
}; };
// default multisampleStateCI
vk::PipelineMultisampleStateCreateInfo multisampleStateCI { vk::PipelineMultisampleStateCreateInfo multisampleStateCI {
.rasterizationSamples = vk::SampleCountFlagBits::e1, .rasterizationSamples = vk::SampleCountFlagBits::e1,
.sampleShadingEnable = VK_FALSE, .sampleShadingEnable = VK_FALSE,
@ -491,25 +469,27 @@ using std::uint32_t;
/* .alphaToOneEnable = VK_FALSE, */ /* .alphaToOneEnable = VK_FALSE, */
}; };
// default colorBlendStateCI
vk::PipelineColorBlendAttachmentState colorBlendAttachment { vk::PipelineColorBlendAttachmentState colorBlendAttachment {
.blendEnable = VK_FALSE, /* .blendEnable = VK_FALSE, */
/* .srcColorBlendFactor = vk::BlendFactor::eOne, */ .blendEnable = VK_TRUE,
/* .dstColorBlendFactor = vk::BlendFactor::eZero, */ .srcColorBlendFactor = vk::BlendFactor::eOne,
/* .colorBlendOp = vk::BlendOp::eAdd, */ .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
/* .srcAlphaBlendFactor = vk::BlendFactor::eOne, */ .colorBlendOp = vk::BlendOp::eAdd,
/* .dstAlphaBlendFactor = vk::BlendFactor::eZero, */ .srcAlphaBlendFactor = vk::BlendFactor::eOne,
/* .alphaBlendOp = vk::BlendOp::eAdd, */ .dstAlphaBlendFactor = vk::BlendFactor::eOne,
.alphaBlendOp = vk::BlendOp::eAdd,
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
}; };
vk::PipelineColorBlendStateCreateInfo colorBlendCI { vk::PipelineColorBlendStateCreateInfo colorBlendStateCI {
.logicOpEnable = VK_FALSE, .logicOpEnable = VK_FALSE,
}; };
colorBlendCI.setAttachments(colorBlendAttachment); colorBlendStateCI.setAttachments(colorBlendAttachment);
colorBlendCI.blendConstants[0] = 0.0f; colorBlendStateCI.blendConstants[0] = 0.0f;
colorBlendCI.blendConstants[1] = 0.0f; colorBlendStateCI.blendConstants[1] = 0.0f;
colorBlendCI.blendConstants[2] = 0.0f; colorBlendStateCI.blendConstants[2] = 0.0f;
colorBlendCI.blendConstants[3] = 0.0f; colorBlendStateCI.blendConstants[3] = 0.0f;
/* std::vector<vk::DynamicState> dynamicStates = { */ /* std::vector<vk::DynamicState> dynamicStates = { */
/* vk::DynamicState::eViewport, */ /* vk::DynamicState::eViewport, */
@ -519,7 +499,8 @@ using std::uint32_t;
/* dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size()); */ /* dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size()); */
/* dynamicState.pDynamicStates = dynamicStates.data(); */ /* dynamicState.pDynamicStates = dynamicStates.data(); */
vk::PipelineDepthStencilStateCreateInfo depthStencilCI { // default depthStencilStateCI
vk::PipelineDepthStencilStateCreateInfo depthStencilStateCI {
.depthTestEnable = VK_TRUE, .depthTestEnable = VK_TRUE,
.depthWriteEnable = VK_TRUE, .depthWriteEnable = VK_TRUE,
.depthCompareOp = vk::CompareOp::eLess, .depthCompareOp = vk::CompareOp::eLess,
@ -532,45 +513,38 @@ using std::uint32_t;
}; };
vk::PipelineLayoutCreateInfo pipelineLayoutCI; vk::PipelineLayoutCreateInfo pipelineLayoutCI;
// TODO
/* pipelineLayoutCI.setPushConstantRanges() */ /* pipelineLayoutCI.setPushConstantRanges() */
pipelineLayoutCI.setSetLayouts(descriptorSetLayouts);
if (descriptorSetLayouts != nullptr) {
pipelineLayoutCI.setSetLayouts(*descriptorSetLayouts);
}
vk::Result result = device.createPipelineLayout(&pipelineLayoutCI, nullptr, &pipeline.layout); vk::Result result = device.createPipelineLayout(&pipelineLayoutCI, nullptr, &pipeline.layout);
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to create pipeline layout", "VulkanInstance::createGraphicsPipeline"); throw getVkException(result, "Failed to create pipeline layout", "VulkanInstance::createGraphicsPipeline");
} }
vk::GraphicsPipelineCreateInfo pipelineCI { pipelineCI.setLayout(pipeline.layout);
.pVertexInputState = &vertexInputStateCI,
.pInputAssemblyState = &inputAssemblyStateCI, if (pipelineCI.pVertexInputState == nullptr) { pipelineCI.setPVertexInputState(&vertexInputStateCI); }
.pViewportState = &viewportStateCI, if (pipelineCI.pInputAssemblyState == nullptr) { pipelineCI.setPInputAssemblyState(&inputAssemblyStateCI); }
.pRasterizationState = &rasterizerCI, if (pipelineCI.pViewportState == nullptr) { pipelineCI.setPViewportState(&viewportStateCI); }
.pMultisampleState = &multisampleStateCI, if (pipelineCI.pRasterizationState == nullptr) { pipelineCI.setPRasterizationState(&rasterizationStateCI); }
.pDepthStencilState = useDepthStencil ? &depthStencilCI : nullptr, if (pipelineCI.pMultisampleState == nullptr) { pipelineCI.setPMultisampleState(&multisampleStateCI); }
.pColorBlendState = &colorBlendCI, if (useDepthStencil and pipelineCI.pDepthStencilState == nullptr) { pipelineCI.setPDepthStencilState(&depthStencilStateCI); }
/* .pDynamicState = nullptr, */ if (pipelineCI.pColorBlendState == nullptr) { pipelineCI.setPColorBlendState(&colorBlendStateCI); }
.layout = pipeline.layout,
.renderPass = renderPass,
.subpass = 0,
/* .basePipelineHandle = VK_NULL_HANDLE, */
/* .basePipelineIndex = -1, */
};
pipelineCI.setStages(shaderStagesCI);
// result, vector<pipeline> // 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(); pipeline.pipeline = pipelines.front();
if (result2 != vk::Result::eSuccess) { if (result2 != vk::Result::eSuccess) {
throw getVkException(result, "Could not create graphics pipeline", "createGraphicsPipeline"); throw getVkException(result, "Could not create graphics pipeline", "createGraphicsPipeline");
} }
device.destroyShaderModule(vertShaderModule, nullptr);
device.destroyShaderModule(fragShaderModule, nullptr);
vLog.log0("createGraphicsPipeline: Created graphics pipeline."); 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<Vertex2D>(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline);
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<Vertex3D>(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline);
// SHADER MODULE // SHADER MODULE
@ -587,6 +561,21 @@ using std::uint32_t;
return shaderModule; 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 // 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) { 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 // FRAMEBUFFERS
void VulkanInstance::createFramebuffers(std::vector<vk::Framebuffer>& framebuffers, std::vector<vk::ImageView>& imageViews, vk::RenderPass& renderPass, vk::ImageView depthImageView) { 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 { vk::FramebufferCreateInfo framebufferCI {
.renderPass = renderPass, .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 // 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) { 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 { vk::ImageCreateInfo imageCI {
@ -782,7 +826,7 @@ using std::uint32_t;
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to bind image to its memory", "VulkanInstance::createImage"); 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) { void VulkanInstance::transitionImageLayout(vk::Image image, vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::CommandBuffer* cmdBuffer) {
vk::ImageMemoryBarrier2 barrier { vk::ImageMemoryBarrier2 barrier {
.srcAccessMask = NO_ACC_2_FLAGS,
.dstAccessMask = NO_ACC_2_FLAGS,
.oldLayout = oldLayout, .oldLayout = oldLayout,
.newLayout = newLayout, .newLayout = newLayout,
// not using barrier for queue famlily ownership transfer // not using barrier for queue famlily ownership transfer
@ -895,50 +937,45 @@ using std::uint32_t;
InstanceCommandPool commandPool; InstanceCommandPool commandPool;
if (oldLayout == vk::ImageLayout::eUndefined and if (oldLayout == vk::ImageLayout::eUndefined and
newLayout == vk::ImageLayout::eDepthStencilAttachmentOptimal) { newLayout == vk::ImageLayout::eDepthStencilAttachmentOptimal) {
barrier.srcAccessMask = NO_ACC_2_FLAGS;
barrier.dstAccessMask = vk::AccessFlagBits2::eDepthStencilAttachmentRead | vk::AccessFlagBits2::eDepthStencilAttachmentWrite;
barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eDepth; barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eDepth;
if (hasStencilComponent(format)) { if (hasStencilComponent(format)) {
barrier.subresourceRange.aspectMask |= vk::ImageAspectFlagBits::eStencil; barrier.subresourceRange.aspectMask |= vk::ImageAspectFlagBits::eStencil;
} }
barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone;
barrier.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe; barrier.srcAccessMask = vk::AccessFlagBits2::eNone;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eEarlyFragmentTests; barrier.dstStageMask = vk::PipelineStageFlagBits2::eEarlyFragmentTests;
barrier.dstAccessMask = vk::AccessFlagBits2::eDepthStencilAttachmentRead | vk::AccessFlagBits2::eDepthStencilAttachmentWrite;
commandPool = POOL_GRAPHICS; commandPool = POOL_GRAPHICS;
} }
else if (oldLayout == vk::ImageLayout::eUndefined and else if (oldLayout == vk::ImageLayout::eUndefined and
newLayout == vk::ImageLayout::eTransferDstOptimal) { newLayout == vk::ImageLayout::eTransferDstOptimal) {
barrier.srcAccessMask = NO_ACC_2_FLAGS; barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone;
barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; barrier.srcAccessMask = vk::AccessFlagBits2::eNone;
barrier.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer;
barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite;
commandPool = POOL_TRANSFER; commandPool = POOL_TRANSFER;
} }
else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and
newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) {
barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite;
barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead;
barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer;
barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader;
barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead;
commandPool = POOL_GRAPHICS; commandPool = POOL_GRAPHICS;
} }
else if (oldLayout == vk::ImageLayout::eShaderReadOnlyOptimal and else if (oldLayout == vk::ImageLayout::eShaderReadOnlyOptimal and
newLayout == vk::ImageLayout::eTransferDstOptimal) { newLayout == vk::ImageLayout::eTransferDstOptimal) {
barrier.srcAccessMask = vk::AccessFlagBits2::eShaderRead;
barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite;
barrier.srcStageMask = vk::PipelineStageFlagBits2::eFragmentShader; barrier.srcStageMask = vk::PipelineStageFlagBits2::eFragmentShader;
barrier.srcAccessMask = vk::AccessFlagBits2::eShaderRead;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer;
barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite;
commandPool = POOL_GRAPHICS; commandPool = POOL_GRAPHICS;
} }
else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and
newLayout == vk::ImageLayout::ePresentSrcKHR) { newLayout == vk::ImageLayout::ePresentSrcKHR) {
barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer;
barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite;
barrier.dstAccessMask = vk::AccessFlagBits2::eMemoryRead; barrier.dstAccessMask = vk::AccessFlagBits2::eMemoryRead;
barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput; barrier.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput;
commandPool = POOL_GRAPHICS; commandPool = POOL_GRAPHICS;
} }
@ -1489,9 +1526,10 @@ using std::uint32_t;
.imageColorSpace = surfaceFormat.surfaceFormat.colorSpace, .imageColorSpace = surfaceFormat.surfaceFormat.colorSpace,
.imageExtent = scExtent, .imageExtent = scExtent,
.imageArrayLayers = 1, .imageArrayLayers = 1,
// if postProcessing: vk::ImageUsageFlagBits::eTransferDst // transferDst for copying rendered images to swap chain
.imageUsage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst, .imageUsage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst,
.preTransform = scDetails.capabilities.surfaceCapabilities.currentTransform, .preTransform = scDetails.capabilities.surfaceCapabilities.currentTransform,
// TODO
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque, .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque,
.presentMode = selectSwapChainPresentMode(scDetails.presentModes), .presentMode = selectSwapChainPresentMode(scDetails.presentModes),
.clipped = VK_TRUE, .clipped = VK_TRUE,
@ -1522,7 +1560,14 @@ using std::uint32_t;
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
throw getVkException(result, "Couldn not get swap chain images", "VulkanInstance::createSwapChain"); 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(); cleanupSwapChain();
createSwapChain(); createSwapChain();
createSwapChainImageViews();
createCommandBuffers(commandBuffersBegin); createCommandBuffers(commandBuffersBegin);
createCommandBuffers(commandBuffersEnd); createCommandBuffers(commandBuffersEnd);
@ -1552,7 +1596,7 @@ using std::uint32_t;
} }
vLog.log0("recreateSwapChain: Updating all ObjectsUsingVulkan"); vLog.log0("recreateSwapChain: Updating all ObjectsUsingVulkan");
for (auto& obj : VulkanInstance::objectsUsingVulkan) { for (auto& obj : VulkanInstance::objectsUsingVulkan) {
obj.updateHandles(); obj->updateHandles();
} }
} }
@ -1564,15 +1608,6 @@ using std::uint32_t;
device.destroySwapchainKHR(swapChain, nullptr); device.destroySwapchainKHR(swapChain, nullptr);
} }
void VulkanInstance::createSwapChainImageViews() {
scImageViews.resize(scImages.size());
for (unsigned int i = 0; i < scImageViews.size(); i++) {
createImageView(scImageFormat, scImages[i], scImageViews[i], vk::ImageAspectFlagBits::eColor);
}
vLog.log0("createImageViews: Created", scImageViews.size(), "image views.");
}
uint32_t VulkanInstance::findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties) { uint32_t VulkanInstance::findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties) {
for (uint32_t i = 0; i < phDevMemProperties.memoryProperties.memoryTypeCount; i++) { 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 // DEBUG
void VulkanInstance::setupDebugMessenger() { void VulkanInstance::setupDebugMessenger() {
// get the address of the vkCreateDebugUtilsMessengerEXT function // get the address of the vkCreateDebugUtilsMessengerEXT function
@ -1704,7 +1718,7 @@ using std::uint32_t;
// HANDLE OWNERSHIP // HANDLE OWNERSHIP
bool VulkanInstance::lastColorWhite; 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]+)"); const std::regex reAddress(R"(0x[0-9a-f]+)");
std::string VulkanInstance::handleOwnerString(100, ' '); // reserve size 100 std::string VulkanInstance::handleOwnerString(100, ' '); // reserve size 100
@ -1722,8 +1736,8 @@ using std::uint32_t;
ss >> address; ss >> address;
for (auto& obj : objectsUsingVulkan) { for (auto& obj : objectsUsingVulkan) {
/* vLog(address, obj.handles); */ /* vLog(address, obj.handles); */
if (obj.handles.contains(address)) { if (obj->contains(address)) {
handleOwnerString += it->str() + " - " + obj.objectName; handleOwnerString += it->str() + " - " + obj->getName();
address = 0; address = 0;
foundHandle = true; foundHandle = true;
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <memory>
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
/* #include <glm/glm.hpp> */ /* #include <glm/glm.hpp> */
@ -14,8 +15,8 @@
#include "vertex.hpp" #include "vertex.hpp"
#include "vulkan_util.hpp" #include "vulkan_util.hpp"
#include "vulkan_allocator.hpp"
#include "vulkan_allocator.hpp"
#include "vulkan_settings.hpp" #include "vulkan_settings.hpp"
#include <gz-util/log.hpp> #include <gz-util/log.hpp>
@ -67,7 +68,6 @@ namespace gz::vlk {
* -# @ref setValidSettings "set the possible settings for the SettingsManager" * -# @ref setValidSettings "set the possible settings for the SettingsManager"
* -# @ref createLogicalDevice "create a logical device" * -# @ref createLogicalDevice "create a logical device"
* -# @ref createSwapChain "create the swap chain" * -# @ref createSwapChain "create the swap chain"
* -# @ref createSwapChainImageViews "create the swap chain image views"
* -# @ref createCommandPools "create the command pools" * -# @ref createCommandPools "create the command pools"
* @todo move depth image, texture, texture samples, model stuff to renderers * @todo move depth image, texture, texture samples, model stuff to renderers
* -# @ref createCommandBuffers "create command buffers for swap chain image layout transitions" * -# @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 * @brief Register vulkan handles used by another object
* @details * @details
* Use this function to register vulkan handles used by another object. * 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. * be determined and added to the message.
* This makes the debugging process easier when multiple objects use the same type of vulkan handle. * 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); 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 * @brief Create a new graphics pipeline
* @param vertexShader Path to the SPIR-V vertex shader * @params pipelineCI @ref create_pipeline_create_info "(Not necessary fully initalized)" create info struct.
* @param fragmentShader Path to the SPIR-V fragment shader * @param desciptorSetLayouts [Optional] Vector of descriptor set layouts
* @param useDepthStencil Wether to use depth // TODO * @param useDepthStencil Wether to use depth
* @param renderPass The (already created) render pass
* @param pipelineLayout Pipeline layout handle to bind
* @param pipeline Pipeline handle to bind * @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 * @details
* Create a pipeline with: * @section create_pipeline_ci Pipeline Create Info
* - 2 shader stages: vertex and fragment shader * @subsection create_pipeline_ci_optional Optional and default values
* - vk::PrimitiveTopology::eTriangleList, vertices are triangles * The pipelineCI struct does not have to be fully initalized.
* - viewport viewing the whole image as described by scExtent * Some values can be `nullptr`, in which case a default value is used to create the pipeline.
* - scissor with offset (0, 0) * The optional values and their defaults are:
* - rasterizer: * - pVertexInputState: initalized from `VertexT::getBindingDescription()` and `VertexT::getAttributeDescriptions()`
* - triangles are filled with the colors from the vertex (VK_POLYGON_FILL) * - pViewportState: viewport of swap chain extent and scissor of swap chain extent
* - counter clockwise front face (vk::FrontFace::eCounterClockwise) * - 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> 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); 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 * @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); 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); 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); 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 * @name Public Interface: Image utility
* @details * @details
@ -598,8 +621,13 @@ namespace gz::vlk {
*/ */
vk::PresentModeKHR selectSwapChainPresentMode(const std::vector<vk::PresentModeKHR>& availableModes); vk::PresentModeKHR selectSwapChainPresentMode(const std::vector<vk::PresentModeKHR>& availableModes);
vk::Extent2D selectSwapExtent(const vk::SurfaceCapabilities2KHR& capabilities); vk::Extent2D selectSwapExtent(const vk::SurfaceCapabilities2KHR& capabilities);
/**
* @brief Create swap chain, image views
*/
void createSwapChain(); void createSwapChain();
void createSwapChainImageViews(); /**
* @brief Destroy swap chain, image views
*/
void cleanupSwapChain(); void cleanupSwapChain();
/** /**
* @brief Recreate the swap chain for the current window size * @brief Recreate the swap chain for the current window size
@ -647,18 +675,6 @@ namespace gz::vlk {
void createSyncObjects(); 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 * @name Utility
*/ */
@ -682,7 +698,7 @@ namespace gz::vlk {
* @name Debugging: (handle ownership) * @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 * @brief Search for handles in message and get their owners
* @details * @details
@ -702,9 +718,14 @@ namespace gz::vlk {
// //
// IMPLEMENTATIONS // 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 // UNIFORM BUFFERS
//
template<typename T> template<typename T>
void VulkanInstance::createUniformBuffers(std::vector<vk::Buffer>& uniformBuffers, std::vector<MemoryInfo>& uniformBuffersMemory) { void VulkanInstance::createUniformBuffers(std::vector<vk::Buffer>& uniformBuffers, std::vector<MemoryInfo>& uniformBuffersMemory) {
vk::DeviceSize bufferSize = sizeof(T); vk::DeviceSize bufferSize = sizeof(T);
@ -717,9 +738,7 @@ namespace gz::vlk {
} }
} }
// // UTILITY
// UTILITY
//
template<typename T, typename... Args> template<typename T, typename... Args>
vk::Result VulkanInstance::runVkResultFunction(const char* name, Args&&... args) { vk::Result VulkanInstance::runVkResultFunction(const char* name, Args&&... args) {
auto f = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name)); auto f = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name));