registerObjectUsingVulkan signature changed
registerObjectUsingVulkan is now a factory for ObjectUsingVulkan
This commit is contained in:
parent
2169e3ee47
commit
cdae3347a4
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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; */
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
/* #include "vulkan_util.hpp" */
|
||||
#include "vulkan_util.hpp"
|
||||
#include <gz-util/log.hpp>
|
||||
|
||||
#include <initializer_list>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user