moved settings to separate header

This commit is contained in:
matthias@arch 2022-10-27 00:50:24 +02:00
parent 2bc7fe05f2
commit 3adcc72036
34 changed files with 1785 additions and 1779 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ old
shaders shaders
stb_image.h stb_image.h
*.log *.log
vk.xml
textures textures
tiny_obj_loader.h tiny_obj_loader.h
vk_enum_string.h vk_enum_string.h

View File

@ -1,12 +1,16 @@
#!/bin/sh #!/bin/sh
WDIR=$HOME/c++/vulkan WDIR=$HOME/c++/vulkan
SHADER_DIR=$WDIR/shaders
SOURCE_DIR=$WDIR/src/shaders
mkdir -p $WDIR/shaders mkdir -p "${SHADER_DIR}"
glslc $WDIR/shader.vert -o $WDIR/shaders/vert.spv for file in $(ls ${SOURCE_DIR}); do
glslc $WDIR/shader.frag -o $WDIR/shaders/frag.spv ext="${file##*.}"
if [[ $ext == "vert" ]] || [[ $ext == "frag" ]]; then
glslc $WDIR/shader2D.vert -o $WDIR/shaders/vert2D.spv echo "compiling ${file}"
glslc $WDIR/shader2D.frag -o $WDIR/shaders/frag2D.spv glslc ${SOURCE_DIR}/${file} -o ${SHADER_DIR}/$(basename ${file}).spv
fi
done

View File

@ -48,7 +48,10 @@ $(OBJECT_DIRS):
# Extras Options # Extras Options
# #
# with debug flags # with debug flags
.PHONY += debug run gdb pch clean docs .PHONY += shader debug run gdb pch clean docs
shader:
sh ../compile.sh
debug: CXXFLAGS += -g # -DDEBUG debug: CXXFLAGS += -g # -DDEBUG
debug: default debug: default

View File

@ -1,30 +1,31 @@
#include "main.hpp"
#include "shape.hpp" #include "shape.hpp"
#include "vulkan_instance.hpp" #include "vulkan_instance.hpp"
#include "renderer2D.hpp" #include "renderer2D.hpp"
#include "renderer3D.hpp" #include "renderer3D.hpp"
#include "vulkan_settings.hpp"
#include <chrono> #include <chrono>
#include <ratio> #include <ratio>
#include <thread> #include <thread>
namespace gz::vk { namespace gz::vlk {
int mainLoop() { int mainLoop() {
LogCreateInfo logCI{}; LogCreateInfo logCI {
logCI.logfile = "main.log"; .logfile = "main.log",
logCI.storeLog = false; .storeLog = false,
logCI.prefix = "Main"; .prefix = "Main",
logCI.prefixColor = Color::BG_RED; .prefixColor = Color::BG_RED,
logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR,
};
Log log(std::move(logCI)); Log log(std::move(logCI));
gz::SettingsManagerCreateInfo<SettingsTypes> smCI{}; gz::SettingsManagerCreateInfo<VULKAN_SETTINGS_MAN_TYPES> smCI {
smCI.filepath = gz::vk::CONFIG_FILE; .filepath = settings::CONFIG_FILE,
smCI.readFileOnCreation = true; .initialValues = settings::INITIAL_SETTINGS,
smCI.writeFileOnExit = true; .readFileOnCreation = true,
smCI.initialValues = gz::vk::INITIAL_SETTINGS; .writeFileOnExit = true,
smCI.throwExceptionWhenNewValueNotAllowed = true; .throwExceptionWhenNewValueNotAllowed = true,
};
VulkanInstance vulkanInstance(smCI); VulkanInstance vulkanInstance(smCI);
vulkanInstance.init(); vulkanInstance.init();
@ -90,5 +91,5 @@ namespace gz::vk {
int main() { int main() {
return gz::vk::mainLoop(); return gz::vlk::mainLoop();
} }

View File

@ -1,19 +0,0 @@
#pragma once
namespace gz::vk {
} // namespace gz::vk

View File

@ -2,7 +2,7 @@
#include "vulkan_instance.hpp" #include "vulkan_instance.hpp"
namespace gz::vk { namespace gz::vlk {
void Renderer::cleanup_(){ void Renderer::cleanup_(){
vk.destroyCommandBuffers(commandBuffers); vk.destroyCommandBuffers(commandBuffers);

View File

@ -1,16 +1,22 @@
#pragma once #pragma once
#define VULKAN_HPP_NO_CONSTRUCTORS
#define VULKAN_HPP_NO_EXCEPTIONS
#include <vulkan/vulkan.hpp>
// includes for child classes // includes for child classes
#include "vulkan_util.hpp"
#include <gz-util/log.hpp>
#include "texture_manager.hpp" #include "texture_manager.hpp"
#include "vertex.hpp" #include "vertex.hpp"
#include "vulkan_allocator.hpp" #include "vulkan_allocator.hpp"
#include <gz-util/log.hpp>
#include <vulkan/vulkan_core.h>
#include <vector> #include <vector>
namespace gz::vk { namespace gz::vlk {
/// Defined in texture_manager.hpp /// Defined in texture_manager.hpp
class TextureManager; class TextureManager;
/// Defined in vulkan_instance.hpp /// Defined in vulkan_instance.hpp
@ -31,13 +37,13 @@ namespace gz::vk {
VulkanInstance& vk; VulkanInstance& vk;
TextureManager& textureManager; TextureManager& textureManager;
std::vector<VkCommandBuffer> commandBuffers; std::vector<vk::CommandBuffer> commandBuffers;
/// On device local memory /// On device local memory
VkBuffer vertexBuffer; vk::Buffer vertexBuffer;
MemoryInfo vertexBufferMemory; MemoryInfo vertexBufferMemory;
VkDeviceSize vertexBufferSize; vk::DeviceSize vertexBufferSize;
VkBuffer indexBuffer; vk::Buffer indexBuffer;
MemoryInfo indexBufferMemory; MemoryInfo indexBufferMemory;
VkDeviceSize indexBufferSize; vk::DeviceSize indexBufferSize;
}; // class RendererBase }; // class RendererBase
} // namespace gz::vk } // namespace gz::vlk

View File

@ -1,17 +1,16 @@
#include "renderer2D.hpp" #include "renderer2D.hpp"
#include "exceptions.hpp" #include "exceptions.hpp"
#include "vk_enum_string.h"
#include "vulkan_allocator.hpp" #include "vulkan_allocator.hpp"
#include "vulkan_instance.hpp" #include "vulkan_instance.hpp"
#include "texture_manager.hpp" #include "texture_manager.hpp"
#include <cstdint>
#include <cstring> #include <cstring>
#include <stdexcept>
#include <thread> #include <thread>
#include <vulkan/vulkan_core.h>
namespace gz::vlk {
namespace gz::vk {
// //
// INIT & CLEANUP // INIT & CLEANUP
@ -19,12 +18,13 @@ namespace gz::vk {
Renderer2D::Renderer2D(VulkanInstance& instance, TextureManager& textureManager) : Renderer2D::Renderer2D(VulkanInstance& instance, TextureManager& textureManager) :
Renderer(instance, textureManager) Renderer(instance, textureManager)
{ {
LogCreateInfo logCI{}; LogCreateInfo logCI {
logCI.logfile = "renderer2D.log"; .logfile = "renderer2D.log",
logCI.storeLog = false; .storeLog = false,
logCI.prefix = "2D-Renderer"; .prefix = "2D-Renderer",
logCI.prefixColor = Color::LI_MAGENTA; .prefixColor = Color::LI_MAGENTA,
logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR,
};
rLog = Log(std::move(logCI)); rLog = Log(std::move(logCI));
vk.registerCleanupCallback(std::bind(&Renderer2D::cleanup, this)); vk.registerCleanupCallback(std::bind(&Renderer2D::cleanup, this));
@ -59,8 +59,19 @@ namespace gz::vk {
createRenderPass(); createRenderPass();
createImages(); createImages();
vk.createFramebuffers(framebuffers, imageViews, renderPass); vk.createFramebuffers(framebuffers, imageViews, renderPass);
std::vector<VkDescriptorSetLayout> descriptorSetLayouts = { textureManager.getDescriptorSetLayout() }; std::vector<vk::DescriptorSetLayout> descriptorSetLayouts = { textureManager.getDescriptorSetLayout() };
vk.createGraphicsPipeline<Vertex2D>("shaders/vert2D.spv", "shaders/frag2D.spv", descriptorSetLayouts, false, renderPass, pipelines[PL_2D]);
// specialization constant for sampler2D array length = atlas count
vk::SpecializationMapEntry specME {
.constantID = 0,
.offset = 0,
.size = sizeof(uint32_t),
};
uint32_t atlasCount = textureManager.getAtlasCount();
vk::SpecializationInfo specI;
specI.setData<uint32_t>(atlasCount);
specI.setMapEntries(specME);
vk.createGraphicsPipeline<Vertex2D>("shaders/vert2D.spv", "shaders/frag2D.spv", descriptorSetLayouts, false, renderPass, pipelines[PL_2D], &specI);
} }
@ -74,7 +85,7 @@ namespace gz::vk {
vk.destroyImageView(imageViews[i]); vk.destroyImageView(imageViews[i]);
vk.destroyImage(images[i], imageMemory[i]); vk.destroyImage(images[i], imageMemory[i]);
} }
vkDestroyRenderPass(vk.getDevice(), renderPass, nullptr); vk.getDevice().destroyRenderPass(renderPass, nullptr);
} }
@ -93,10 +104,10 @@ namespace gz::vk {
images.resize(vk.getScImages().size()); images.resize(vk.getScImages().size());
imageMemory.resize(vk.getScImages().size()); imageMemory.resize(vk.getScImages().size());
imageViews.resize(vk.getScImages().size()); imageViews.resize(vk.getScImages().size());
VkImageUsageFlags usage= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; vk::ImageUsageFlags usage= vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc;
for (size_t i = 0; i < images.size(); i++) { for (size_t i = 0; i < images.size(); i++) {
vk.createImage(vk.getScExtent().width, vk.getScExtent().height, vk.getScImageFormat(), VK_IMAGE_TILING_OPTIMAL, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, images[i], imageMemory[i]); vk.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_IMAGE_ASPECT_COLOR_BIT); vk.createImageView(vk.getScImageFormat(), images[i], imageViews[i], vk::ImageAspectFlagBits::eColor);
} }
} }
@ -104,87 +115,80 @@ namespace gz::vk {
// RENDER PASS // RENDER PASS
// //
void Renderer2D::createRenderPass() { void Renderer2D::createRenderPass() {
VkAttachmentDescription2 colorBlendAttachment{}; vk::AttachmentDescription2 colorBlendAttachment {
colorBlendAttachment.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; .format = vk.getScImageFormat(),
colorBlendAttachment.format = vk.getScImageFormat(); .samples = vk::SampleCountFlagBits::e1,
colorBlendAttachment.samples = VK_SAMPLE_COUNT_1_BIT; .loadOp = vk::AttachmentLoadOp::eClear,
colorBlendAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; .storeOp = vk::AttachmentStoreOp::eStore,
colorBlendAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; .stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
colorBlendAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; .stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
colorBlendAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; .initialLayout = vk::ImageLayout::eUndefined,
colorBlendAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; .finalLayout = vk::ImageLayout::eTransferSrcOptimal,
colorBlendAttachment.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; };
VkAttachmentReference2 colorAttachmentRef{}; vk::AttachmentReference2 colorAttachmentRef {
colorAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2; .attachment = 0,
colorAttachmentRef.attachment = 0; .layout = vk::ImageLayout::eColorAttachmentOptimal,
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; };
/* VkAttachmentDescription depthAttachment{}; */ /* vk::AttachmentDescription depthAttachment { */
/* depthAttachment.format = findDepthFormat(); */ /* depthAttachment.format = findDepthFormat(); */
/* depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; */ /* depthAttachment.samples = vk::SampleCountFlagBits::e1; */
/* depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; */ /* depthAttachment.loadOp = vk::AttachmentLoadOp::eClear; */
/* depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */ /* depthAttachment.storeOp = vk::AttachmentStoreOp::eDontCare; */
/* depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; */ /* depthAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare; */
/* depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */ /* depthAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare; */
/* depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; */ /* depthAttachment.initialLayout = vk::ImageLayout::eUndefined; */
/* depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */ /* depthAttachment.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; */
/* VkAttachmentReference depthAttachmentRef{}; */ /* vk::AttachmentReference depthAttachmentRef { */
/* depthAttachmentRef.attachment = 1; */ /* depthAttachmentRef.attachment = 1; */
/* depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */ /* depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; */
VkSubpassDescription2 subpass{}; vk::SubpassDescription2 subpass {
subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2; .pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; .colorAttachmentCount = 1,
subpass.colorAttachmentCount = 1; .pColorAttachments = &colorAttachmentRef,
subpass.pColorAttachments = &colorAttachmentRef; /* .pDepthStencilAttachment = &depthAttachmentRef, */
/* subpass.pDepthStencilAttachment = &depthAttachmentRef; */ };
VkSubpassDependency2 colorAttachmentSD{}; vk::SubpassDependency2 colorAttachmentSD {
colorAttachmentSD.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2; .srcSubpass = VK_SUBPASS_EXTERNAL,
colorAttachmentSD.srcSubpass = VK_SUBPASS_EXTERNAL; .dstSubpass = 0,
colorAttachmentSD.dstSubpass = 0; .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
colorAttachmentSD.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; .dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
colorAttachmentSD.srcAccessMask = 0; .srcAccessMask = NO_ACC_FLAGS,
colorAttachmentSD.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
colorAttachmentSD.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; };
// dependecy for the image layout transition to transfer dst // dependecy for the image layout transition to transfer dst
VkSubpassDependency2 layoutTransitionSD{}; vk::SubpassDependency2 layoutTransitionSD {
layoutTransitionSD.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2; .srcSubpass = 0,
layoutTransitionSD.srcSubpass = 0; .dstSubpass = VK_SUBPASS_EXTERNAL,
layoutTransitionSD.dstSubpass = VK_SUBPASS_EXTERNAL; .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
layoutTransitionSD.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; .dstStageMask = vk::PipelineStageFlagBits::eTransfer,
layoutTransitionSD.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
layoutTransitionSD.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; .dstAccessMask = vk::AccessFlagBits::eTransferRead,
layoutTransitionSD.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT; .dependencyFlags = vk::DependencyFlagBits::eByRegion,
layoutTransitionSD.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; };
/* VkSubpassDependency dependency{}; */ /* vk::SubpassDependency dependency { */
/* dependency.srcSubpass = VK_SUBPASS_EXTERNAL; */ /* dependency.srcSubpass = VK_SUBPASS_EXTERNAL; */
/* dependency.dstSubpass = 0; */ /* dependency.dstSubpass = 0; */
/* dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; */ /* dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; */
/* dependency.srcAccessMask = 0; */ /* dependency.srcAccessMask = 0; */
/* dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; */ /* dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; */
/* dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; */ /* dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite; */
/* std::array<VkAttachmentDescription, 2> attachments = { colorBlendAttachment, depthAttachment }; */ /* std::array<vk::AttachmentDescription, 2> attachments = { colorBlendAttachment, depthAttachment }; */
std::vector<VkAttachmentDescription2> attachments = { colorBlendAttachment }; std::vector<vk::AttachmentDescription2> attachments = { colorBlendAttachment };
std::vector<VkSubpassDependency2> dependencies = { colorAttachmentSD, layoutTransitionSD }; std::vector<vk::SubpassDependency2> dependencies = { colorAttachmentSD, layoutTransitionSD };
VkRenderPassCreateInfo2 renderPassCI{}; vk::RenderPassCreateInfo2 renderPassCI;
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2; renderPassCI.setDependencies(dependencies);
renderPassCI.attachmentCount = static_cast<uint32_t>(attachments.size()); renderPassCI.setAttachments(attachments);
renderPassCI.pAttachments = attachments.data(); renderPassCI.setSubpasses(subpass);
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpass; vk::Result result = vk.getDevice().createRenderPass2(&renderPassCI, nullptr, &renderPass);
renderPassCI.dependencyCount = dependencies.size(); if (result != vk::Result::eSuccess) {
renderPassCI.pDependencies = dependencies.data();
/* renderPassCI.dependencyCount = 0; */
/* renderPassCI.pDependencies = nullptr; */
/* renderPassCI.correlatedViewMaskCount = 0; */
/* renderPassCI.pCorrelatedViewMasks = nullptr; */
VkResult result = vkCreateRenderPass2(vk.getDevice(), &renderPassCI, nullptr, &renderPass);
if (result != VK_SUCCESS) {
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.");
@ -196,54 +200,55 @@ namespace gz::vk {
// RENDERING // RENDERING
// //
void Renderer2D::recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame) { void Renderer2D::recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame) {
VkCommandBufferBeginInfo commandBufferBI{}; vk::CommandBufferBeginInfo commandBufferBI {
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; /* .flags = 0, */
/* commandBufferBI.flags = 0; */ /* .pInheritanceInfo = nullptr, */
/* commandBufferBI.pInheritanceInfo = nullptr; */ };
VkResult result = vkBeginCommandBuffer(commandBuffers[currentFrame], &commandBufferBI); vk::Result result = commandBuffers[currentFrame].begin(&commandBufferBI);
if (result != VK_SUCCESS) { if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to begin 2D command buffer", "Renderer2D::recordCommandBuffer"); throw getVkException(result, "Failed to begin 2D command buffer", "Renderer2D::recordCommandBuffer");
} }
VkRenderPassBeginInfo renderPassBI{};
renderPassBI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBI.renderPass = renderPass;
renderPassBI.framebuffer = framebuffers[imageIndex];
renderPassBI.renderArea.offset = { 0, 0 };
renderPassBI.renderArea.extent = vk.getScExtent();
// clear // clear
std::array<VkClearValue, 1> clearValues{}; std::array<vk::ClearValue, 1> clearValues{};
clearValues[0].color = {{1.0f, 0.0f, 0.0f, 1.0f}}; vk::ClearColorValue clearColor{};
clearColor.setFloat32({ 0.0f, 0.0f, 0.1f, 0.5f });
clearValues[0].setColor(std::move(clearColor));
/* clearValues[1].depthStencil = {1.0f, 0}; */ /* clearValues[1].depthStencil = {1.0f, 0}; */
renderPassBI.clearValueCount = static_cast<uint32_t>(clearValues.size()); vk::RenderPassBeginInfo renderPassBI {
renderPassBI.pClearValues = clearValues.data(); .renderPass = renderPass,
.framebuffer = framebuffers[imageIndex],
.renderArea { .offset = { 0, 0 }, .extent = vk.getScExtent(), }
};
renderPassBI.setClearValues(clearValues);
vkCmdBeginRenderPass(commandBuffers[currentFrame], &renderPassBI, VK_SUBPASS_CONTENTS_INLINE); commandBuffers[currentFrame].beginRenderPass(&renderPassBI, vk::SubpassContents::eInline);
vkCmdBindPipeline(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[PL_2D].pipeline); commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[PL_2D].pipeline);
VkBuffer vertexBuffers[] = { vertexBuffer }; vk::Buffer vertexBuffers[] = { vertexBuffer };
VkDeviceSize offsets[] = {0}; vk::DeviceSize offsets[] = {0};
uint32_t bindingCount = 1; uint32_t bindingCount = 1;
vkCmdBindVertexBuffers(commandBuffers[currentFrame], BINDING, bindingCount, vertexBuffers, offsets); uint32_t binding = 0;
commandBuffers[currentFrame].bindVertexBuffers(binding, bindingCount, vertexBuffers, offsets);
// TODO use correct index type! // TODO use correct index type!
vkCmdBindIndexBuffer(commandBuffers[currentFrame], indexBuffer, NO_OFFSET, VK_INDEX_TYPE_UINT32); commandBuffers[currentFrame].bindIndexBuffer(indexBuffer, NO_OFFSET, vk::IndexType::eUint32);
uint32_t descriptorCount = 1; uint32_t descriptorCount = 1;
uint32_t firstSet = 0; uint32_t firstSet = 0;
uint32_t dynamicOffsetCount = 0; uint32_t dynamicOffsetCount = 0;
uint32_t* dynamicOffsets = nullptr; uint32_t* dynamicOffsets = nullptr;
vkCmdBindDescriptorSets(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[PL_2D].layout, firstSet, descriptorCount, &textureManager.getDescriptorSet(), dynamicOffsetCount, dynamicOffsets); commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelines[PL_2D].layout, firstSet, descriptorCount, &textureManager.getDescriptorSet(), dynamicOffsetCount, dynamicOffsets);
int instanceCount = 1; int instanceCount = 1;
int firstIndex = 0; int firstIndex = 0;
int firstInstance = 0; int firstInstance = 0;
vkCmdDrawIndexed(commandBuffers[currentFrame], static_cast<uint32_t>(shapesIndicesCount), instanceCount, firstIndex, NO_OFFSET, firstInstance); commandBuffers[currentFrame].drawIndexed(static_cast<uint32_t>(shapesIndicesCount), instanceCount, firstIndex, NO_OFFSET, firstInstance);
vkCmdEndRenderPass(commandBuffers[currentFrame]); 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 = vkEndCommandBuffer(commandBuffers[currentFrame]); result = commandBuffers[currentFrame].end();
if (result != VK_SUCCESS) { if (result != vk::Result::eSuccess) {
rLog.error("Failed to record 2D - command buffer", "VkResult:", STR_VK_RESULT(result)); rLog.error("Failed to record 2D - command buffer", "VkResult:", result);
throw getVkException(result, "Failed to record 2D - command buffer", "Renderer2D::recordCommandBufferWithTexture"); throw getVkException(result, "Failed to record 2D - command buffer", "Renderer2D::recordCommandBufferWithTexture");
} }
vk.submitThisFrame(commandBuffers[currentFrame]); vk.submitThisFrame(commandBuffers[currentFrame]);
@ -257,21 +262,24 @@ namespace gz::vk {
} }
// create staging buffer // create staging buffer
VkBuffer stagingBuffer; vk::Buffer stagingBuffer;
MemoryInfo stagingBufferMemory; MemoryInfo stagingBufferMemory;
vk.createBuffer(vertexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); vk.createBuffer(vertexBufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory);
// fill staging buffer // fill staging buffer
void* data; void* data;
vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, vertexBufferSize, NO_FLAGS, &data); vk::Result result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, vertexBufferSize, NO_MEM_FLAGS, &data);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to map staging buffer", "Renderer3D::fillVertexBufferWithShapes");
}
Vertex2D* vdata = reinterpret_cast<Vertex2D*>(data); Vertex2D* vdata = reinterpret_cast<Vertex2D*>(data);
size_t offset = 0; size_t offset = 0;
for (auto it = shapes.begin(); it != shapes.end(); it++) { for (auto it = shapes.begin(); it != shapes.end(); it++) {
rLog("fillVertexBufferWithShapes: copying vertex buffer nr", it - shapes.begin(), "-", it->getVertices(), "to address:", long(vdata + offset), " offset:", offset); rLog.log0("fillVertexBufferWithShapes: copying vertex buffer nr", it - shapes.begin(), "-", it->getVertices(), "to address:", long(vdata + offset), " offset:", offset);
memcpy(vdata+offset, it->getVertices().data(), it->getVertices().size() * sizeof(Vertex2D)); memcpy(vdata+offset, it->getVertices().data(), it->getVertices().size() * sizeof(Vertex2D));
offset += it->getVertices().size(); offset += it->getVertices().size();
} }
vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); vk.getDevice().unmapMemory(stagingBufferMemory.memory);
// fill vertex buffer // fill vertex buffer
vk.copyBuffer(stagingBuffer, vertexBuffer, vertexBufferSize); vk.copyBuffer(stagingBuffer, vertexBuffer, vertexBufferSize);
vk.destroyBuffer(stagingBuffer, stagingBufferMemory); vk.destroyBuffer(stagingBuffer, stagingBufferMemory);
@ -283,13 +291,16 @@ namespace gz::vk {
} }
// create staging buffer // create staging buffer
VkBuffer stagingBuffer; vk::Buffer stagingBuffer;
MemoryInfo stagingBufferMemory; MemoryInfo stagingBufferMemory;
vk.createBuffer(indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); vk.createBuffer(indexBufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory);
// fill staging buffer // fill staging buffer
void* data; void* data;
vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, indexBufferSize, NO_FLAGS, &data); vk::Result result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, indexBufferSize, NO_MEM_FLAGS, &data);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to map staging buffer", "Renderer2D::fillIndexBufferWithShapes");
}
uint32_t* idata = reinterpret_cast<uint32_t*>(data); uint32_t* idata = reinterpret_cast<uint32_t*>(data);
size_t offset = 0; size_t offset = 0;
for (auto it = shapes.begin(); it != shapes.end(); it++) { for (auto it = shapes.begin(); it != shapes.end(); it++) {
@ -297,8 +308,8 @@ namespace gz::vk {
memcpy(idata+offset, it->getIndices().data(), it->getIndices().size() * sizeof(uint32_t)); memcpy(idata+offset, it->getIndices().data(), it->getIndices().size() * sizeof(uint32_t));
offset += it->getIndices().size(); offset += it->getIndices().size();
} }
rLog("fillIndexBufferWithShapes: indices count:", shapesIndicesCount); rLog.log0("fillIndexBufferWithShapes: indices count:", shapesIndicesCount);
vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); vk.getDevice().unmapMemory(stagingBufferMemory.memory);
// fill index buffer // fill index buffer
vk.copyBuffer(stagingBuffer, indexBuffer, indexBufferSize); vk.copyBuffer(stagingBuffer, indexBuffer, indexBufferSize);
@ -320,11 +331,11 @@ namespace gz::vk {
void Renderer2D::drawFrame(uint32_t imageIndex) { void Renderer2D::drawFrame(uint32_t imageIndex) {
vkResetCommandBuffer(commandBuffers[vk.getCurrentFrame()], NO_FLAGS); commandBuffers[vk.getCurrentFrame()].reset();
/* recordCommandBuffer(imageIndex, vk.getCurrentFrame()); */ /* recordCommandBuffer(imageIndex, vk.getCurrentFrame()); */
recordCommandBuffer(imageIndex, vk.getCurrentFrame()); recordCommandBuffer(imageIndex, vk.getCurrentFrame());
} }
} // namespace gz::vk } // namespace gz::vlk

View File

@ -6,7 +6,7 @@
#include "vulkan_allocator.hpp" #include "vulkan_allocator.hpp"
#include "vulkan_util.hpp" #include "vulkan_util.hpp"
namespace gz::vk { namespace gz::vlk {
class Renderer2D : public Renderer { class Renderer2D : public Renderer {
public: public:
/** /**
@ -49,13 +49,13 @@ namespace gz::vk {
* @details * @details
* As of now, this does (in the same command buffer from graphicsPool) * As of now, this does (in the same command buffer from graphicsPool)
* -# begin render pass * -# begin render pass
* - image layout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL * - image layout: vk::ImageLayout::eColorAttachmentOptimal
* - clear image * - clear image
* -# bind 2d pipeline, vertex and index buffer * -# bind 2d pipeline, vertex and index buffer
* -# bind texture sampler * -# bind texture sampler
* -# draw indexed: draw the shapes from shapes vector * -# draw indexed: draw the shapes from shapes vector
* -# end render pass * -# end render pass
* - image layout: VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL * - image layout: vk::ImageLayout::eTransferSrcOptimal
* -# copy image to swapChain image with same imageIndex * -# copy image to swapChain image with same imageIndex
*/ */
void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame); void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame);
@ -67,9 +67,9 @@ namespace gz::vk {
* The images are used as render targets. After rendering, the current image gets blitted onto the current swap chain image. * The images are used as render targets. After rendering, the current image gets blitted onto the current swap chain image.
* @{ * @{
*/ */
std::vector<VkImage> images; std::vector<vk::Image> images;
std::vector<MemoryInfo> imageMemory; std::vector<MemoryInfo> imageMemory;
std::vector<VkImageView> imageViews; std::vector<vk::ImageView> imageViews;
/** /**
* @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images * @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images
*/ */
@ -81,10 +81,10 @@ namespace gz::vk {
* @details * @details
* Attachments: * Attachments:
* - color blend: * - color blend:
* - loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR * - loadOp = vk::AttachmentLoadOp::eClear
* - storeOp = VK_ATTACHMENT_STORE_OP_STORE * - storeOp = vk::AttachmentStoreOp::eStore
* - initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL * - initialLayout = vk::ImageLayout::eColorAttachmentOptimal
* - finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL * - finalLayout = vk::ImageLayout::eColorAttachmentOptimal
* - stencil load/store = dont care * - stencil load/store = dont care
*/ */
/// @{ /// @{
@ -92,10 +92,10 @@ namespace gz::vk {
* @brief Create a render pass * @brief Create a render pass
*/ */
void createRenderPass(); void createRenderPass();
VkRenderPass renderPass; vk::RenderPass renderPass;
/// @} /// @}
std::vector<VkFramebuffer> framebuffers; std::vector<vk::Framebuffer> framebuffers;
// PIPELINE // PIPELINE
PipelineContainer pipelines; PipelineContainer pipelines;
@ -130,4 +130,4 @@ namespace gz::vk {
Log rLog; Log rLog;
}; };
} // namespace gz::vk } // namespace gz::vlk

View File

@ -6,23 +6,24 @@
#include "texture_manager.hpp" #include "texture_manager.hpp"
#include "exceptions.hpp" #include "exceptions.hpp"
#include "vk_enum_string.h" #include "vk_enum_string.h"
#include "vulkan_settings.hpp"
#include <cstring> #include <cstring>
#include <vulkan/vulkan_core.h>
#include <chrono> #include <chrono>
namespace gz::vk { namespace gz::vlk {
// //
// INIT & CLEANUP // INIT & CLEANUP
// //
Renderer3D::Renderer3D(VulkanInstance& instance, TextureManager& textureManager) : Renderer3D::Renderer3D(VulkanInstance& instance, TextureManager& textureManager) :
Renderer(instance, textureManager) { Renderer(instance, textureManager) {
LogCreateInfo logCI{}; LogCreateInfo logCI{
logCI.logfile = "renderer3D.log"; .logfile = "renderer3D.log",
logCI.storeLog = false; .storeLog = false,
logCI.prefix = "3D-Renderer"; .prefix = "3D-Renderer",
logCI.prefixColor = Color::LI_CYAN; .prefixColor = Color::LI_CYAN,
logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR,
};
rLog = Log(std::move(logCI)); rLog = Log(std::move(logCI));
vk.registerCleanupCallback(std::bind(&Renderer3D::cleanup, this)); vk.registerCleanupCallback(std::bind(&Renderer3D::cleanup, this));
@ -33,7 +34,6 @@ namespace gz::vk {
const size_t indexCount = 10000; const size_t indexCount = 10000;
vk.createVertexBuffer<Vertex3D>(vertexCount, vertexBuffer, vertexBufferMemory, vertexBufferSize); vk.createVertexBuffer<Vertex3D>(vertexCount, vertexBuffer, vertexBufferMemory, vertexBufferSize);
vk.createIndexBuffer<uint32_t>(indexCount, indexBuffer, indexBufferMemory, indexBufferSize); vk.createIndexBuffer<uint32_t>(indexCount, indexBuffer, indexBufferMemory, indexBufferSize);
rLog("Created Renderer3D");
// TODO // TODO
loadModel(); loadModel();
@ -46,7 +46,7 @@ namespace gz::vk {
&descriptorSetLayout, &descriptorPool, }, &descriptorSetLayout, &descriptorPool, },
{ &framebuffers, &images, &imageMemory, &imageViews, &commandBuffers, { &framebuffers, &images, &imageMemory, &imageViews, &commandBuffers,
&descriptorSets })); &descriptorSets }));
rLog("Created Renderer3D"); rLog.log1("Created Renderer3D");
} }
void Renderer3D::cleanup() { void Renderer3D::cleanup() {
@ -55,8 +55,8 @@ namespace gz::vk {
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]);
} }
vkDestroyDescriptorSetLayout(vk.getDevice(), descriptorSetLayout, NO_ALLOC); vk.getDevice().destroyDescriptorSetLayout(descriptorSetLayout, NO_ALLOC);
vkDestroyDescriptorPool(vk.getDevice(), descriptorPool, NO_ALLOC); vk.getDevice().destroyDescriptorPool(descriptorPool, NO_ALLOC);
cleanupSwapChainDependantResources(); cleanupSwapChainDependantResources();
cleanup_(); cleanup_();
@ -67,11 +67,13 @@ namespace gz::vk {
// SWAPCHAIN DEPENDANT // SWAPCHAIN DEPENDANT
// //
void Renderer3D::initSwapChainDependantResources() { void Renderer3D::initSwapChainDependantResources() {
// UPDATE DOC ON CHANGES!
createRenderPass(); createRenderPass();
createImages(); createImages();
vk.createFramebuffers(framebuffers, imageViews, renderPass); createDepthImage();
std::vector<VkDescriptorSetLayout> descriptorSetLayouts = { descriptorSetLayout }; vk.createFramebuffers(framebuffers, imageViews, renderPass, depthImageView);
vk.createGraphicsPipeline<Vertex3D>("shaders/vert.spv", "shaders/frag.spv", descriptorSetLayouts, false, renderPass, pipelines[PL_3D]); std::vector<vk::DescriptorSetLayout> descriptorSetLayouts = { descriptorSetLayout };
vk.createGraphicsPipeline<Vertex3D>("shaders/vert.spv", "shaders/frag.spv", descriptorSetLayouts, true, renderPass, pipelines[PL_3D]);
} }
@ -81,13 +83,14 @@ namespace gz::vk {
vk.destroyFramebuffers(framebuffers); vk.destroyFramebuffers(framebuffers);
vk.destroyImageView(depthImageView);
vk.destroyImage(depthImage, depthImageMemory);
for (size_t i = 0; i < images.size(); i++) { for (size_t i = 0; i < images.size(); i++) {
vk.destroyImageView(imageViews[i]); vk.destroyImageView(imageViews[i]);
vk.destroyImage(images[i], imageMemory[i]); vk.destroyImage(images[i], imageMemory[i]);
} }
vkDestroyRenderPass(vk.getDevice(), renderPass, nullptr); vk.getDevice().destroyRenderPass(renderPass, nullptr);
} }
@ -104,99 +107,120 @@ namespace gz::vk {
images.resize(vk.getScImages().size()); images.resize(vk.getScImages().size());
imageMemory.resize(vk.getScImages().size()); imageMemory.resize(vk.getScImages().size());
imageViews.resize(vk.getScImages().size()); imageViews.resize(vk.getScImages().size());
VkImageUsageFlags usage= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; vk::ImageUsageFlags usage= vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc;
for (size_t i = 0; i < images.size(); i++) { for (size_t i = 0; i < images.size(); i++) {
vk.createImage(vk.getScExtent().width, vk.getScExtent().height, vk.getScImageFormat(), VK_IMAGE_TILING_OPTIMAL, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, images[i], imageMemory[i]); vk.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_IMAGE_ASPECT_COLOR_BIT); vk.createImageView(vk.getScImageFormat(), images[i], imageViews[i], vk::ImageAspectFlagBits::eColor);
} }
} }
//
// DEPTH
//
void Renderer3D::createDepthImage() {
vk::MemoryPropertyFlags memoryProperties = vk::MemoryPropertyFlagBits::eDeviceLocal;
vk::ImageUsageFlags imageUsage = vk::ImageUsageFlagBits::eDepthStencilAttachment;
vk::ImageTiling tiling = vk::ImageTiling::eOptimal;
vk::Format depthFormat = vk.getDepthFormat();
vk.createImage(vk.getScExtent().width, vk.getScExtent().height, depthFormat, tiling, imageUsage, memoryProperties, depthImage, depthImageMemory);
vk.createImageView(depthFormat, depthImage, depthImageView, vk::ImageAspectFlagBits::eDepth);
vk.transitionImageLayout(depthImage, depthFormat, vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthStencilAttachmentOptimal);
}
// //
// RENDER PASS // RENDER PASS
// //
void Renderer3D::createRenderPass() { void Renderer3D::createRenderPass() {
VkAttachmentDescription2 colorBlendAttachment{}; vk::AttachmentDescription2 colorBlendAD {
colorBlendAttachment.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; .format = vk.getScImageFormat(),
colorBlendAttachment.format = vk.getScImageFormat(); .samples = vk::SampleCountFlagBits::e1,
colorBlendAttachment.samples = VK_SAMPLE_COUNT_1_BIT; .loadOp = vk::AttachmentLoadOp::eClear,
colorBlendAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; .storeOp = vk::AttachmentStoreOp::eStore,
colorBlendAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; .stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
colorBlendAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; .stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
colorBlendAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; .initialLayout = vk::ImageLayout::eUndefined,
colorBlendAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; .finalLayout = vk::ImageLayout::eTransferSrcOptimal,
colorBlendAttachment.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; };
VkAttachmentReference2 colorAttachmentRef{}; vk::AttachmentReference2 colorBlendAR {
colorAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2; .attachment = 0,
colorAttachmentRef.attachment = 0; .layout = vk::ImageLayout::eColorAttachmentOptimal,
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; };
/* VkAttachmentDescription depthAttachment{}; */ vk::AttachmentDescription2 depthAD {
/* depthAttachment.format = findDepthFormat(); */ .format = vk.getDepthFormat(),
/* depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; */ .samples = vk::SampleCountFlagBits::e1,
/* depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; */ .loadOp = vk::AttachmentLoadOp::eClear,
/* depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */ .storeOp = vk::AttachmentStoreOp::eDontCare,
/* depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; */ .stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
/* depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; */ .stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
/* depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; */ .initialLayout = vk::ImageLayout::eUndefined,
/* depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */ .finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal,
};
/* VkAttachmentReference depthAttachmentRef{}; */ vk::AttachmentReference2 depthAR {
/* depthAttachmentRef.attachment = 1; */ .attachment = 1,
/* depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; */ .layout = vk::ImageLayout::eDepthStencilAttachmentOptimal,
};
VkSubpassDescription2 subpass{}; vk::SubpassDescription2 subpass {
subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2; .pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; .colorAttachmentCount = 1,
subpass.colorAttachmentCount = 1; .pColorAttachments = &colorBlendAR,
subpass.pColorAttachments = &colorAttachmentRef; .pDepthStencilAttachment = &depthAR,
/* subpass.pDepthStencilAttachment = &depthAttachmentRef; */ };
VkSubpassDependency2 colorAttachmentSD{}; // wait until image is available
colorAttachmentSD.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2; vk::SubpassDependency2 colorAttachmentSD {
colorAttachmentSD.srcSubpass = VK_SUBPASS_EXTERNAL; .srcSubpass = VK_SUBPASS_EXTERNAL,
colorAttachmentSD.dstSubpass = 0; .dstSubpass = 0,
colorAttachmentSD.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests,
colorAttachmentSD.srcAccessMask = 0; .dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests,
colorAttachmentSD.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; .srcAccessMask = NO_ACC_FLAGS,
colorAttachmentSD.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; .dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite,
};
// dependecy for the image layout transition to transfer dst // image layout transition to transfer dst
VkSubpassDependency2 layoutTransitionSD{}; vk::SubpassDependency2 layoutTransitionSD {
layoutTransitionSD.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2; .srcSubpass = 0,
layoutTransitionSD.srcSubpass = 0; .dstSubpass = VK_SUBPASS_EXTERNAL,
layoutTransitionSD.dstSubpass = VK_SUBPASS_EXTERNAL; .srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
layoutTransitionSD.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; .dstStageMask = vk::PipelineStageFlagBits::eTransfer,
layoutTransitionSD.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; .srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
layoutTransitionSD.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; .dstAccessMask = vk::AccessFlagBits::eTransferRead,
layoutTransitionSD.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT; .dependencyFlags = vk::DependencyFlagBits::eByRegion,
layoutTransitionSD.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; };
VkSubpassDependency dependency{};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
/* std::array<VkAttachmentDescription, 2> attachments = { colorBlendAttachment, depthAttachment }; */ /* vk::SubpassDependency2 dependency { */
std::vector<VkAttachmentDescription2> attachments = { colorBlendAttachment }; /* dependency.srcSubpass = VK_SUBPASS_EXTERNAL; */
std::vector<VkSubpassDependency2> dependencies = { colorAttachmentSD, layoutTransitionSD }; /* dependency.dstSubpass = 0; */
VkRenderPassCreateInfo2 renderPassCI{}; /* dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; */
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2; /* dependency.srcAccessMask = 0; */
renderPassCI.attachmentCount = static_cast<uint32_t>(attachments.size()); /* dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests; */
renderPassCI.pAttachments = attachments.data(); /* dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite; */
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpass; std::vector<vk::AttachmentDescription2> attachments = { colorBlendAD, depthAD, };
renderPassCI.dependencyCount = dependencies.size(); std::vector<vk::SubpassDependency2> dependencies = { colorAttachmentSD, layoutTransitionSD };
renderPassCI.pDependencies = dependencies.data(); vk::RenderPassCreateInfo2 renderPassCI {
/* renderPassCI.dependencyCount = 0; */ /* .attachmentCount = static_cast<uint32_t>(attachments.size()), */
/* renderPassCI.pDependencies = nullptr; */ /* .pAttachments = attachments.data(), */
/* renderPassCI.correlatedViewMaskCount = 0; */ /* .subpassCount = 1, */
/* renderPassCI.pCorrelatedViewMasks = nullptr; */ /* .pSubpasses = &subpass, */
VkResult result = vkCreateRenderPass2(vk.getDevice(), &renderPassCI, nullptr, &renderPass); /* .dependencyCount = static_cast<uint32_t>(dependencies.size()), */
if (result != VK_SUCCESS) { /* .pDependencies = dependencies.data(), */
/* .dependencyCount = 0, */
/* .pDependencies = nullptr, */
/* .correlatedViewMaskCount = 0, */
/* .pCorrelatedViewMasks = nullptr, */
};
renderPassCI.setAttachments(attachments);
renderPassCI.setDependencies(dependencies);
renderPassCI.setSubpasses(subpass);
vk::Result result = vk.getDevice().createRenderPass2(&renderPassCI, nullptr, &renderPass);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Could not create render pass", "Renderer3D::createRenderPass"); throw getVkException(result, "Could not create render pass", "Renderer3D::createRenderPass");
} }
rLog.log0("createRenderPass: Created render pass."); rLog.log0("createRenderPass: Created render pass.");
@ -210,91 +234,90 @@ namespace gz::vk {
void Renderer3D::createDescriptorResources() { void Renderer3D::createDescriptorResources() {
// LAYOUT // LAYOUT
// 1) uniform buffer object // 1) uniform buffer object
VkDescriptorSetLayoutBinding uboLayoutBinding{}; vk::DescriptorSetLayoutBinding uboLayoutBinding {
uboLayoutBinding.binding = 0; .binding = 0,
uboLayoutBinding.descriptorCount = 1; .descriptorType = vk::DescriptorType::eUniformBuffer,
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; .descriptorCount = 1,
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; .stageFlags = vk::ShaderStageFlagBits::eVertex,
/* uboLayoutBinding.pImmutableSamplers = nullptr; */ /* .pImmutableSamplers = nullptr, */
};
// 2) combined image sampler // 2) combined image sampler
VkDescriptorSetLayoutBinding samplerLayoutBinding{}; vk::DescriptorSetLayoutBinding samplerLayoutBinding {
samplerLayoutBinding.binding = 1; .binding = 1,
samplerLayoutBinding.descriptorCount = 1; .descriptorType = vk::DescriptorType::eCombinedImageSampler,
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; .descriptorCount = 1,
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; .stageFlags = vk::ShaderStageFlagBits::eFragment,
/* samplerLayoutBinding.pImmutableSamplers = nullptr; */ /* .pImmutableSamplers = nullptr, */
};
std::vector<VkDescriptorSetLayoutBinding> bindings = { uboLayoutBinding, samplerLayoutBinding }; std::vector<vk::DescriptorSetLayoutBinding> bindings = { uboLayoutBinding, samplerLayoutBinding };
vk.createDescriptorSetLayout(bindings, descriptorSetLayout); vk.createDescriptorSetLayout(bindings, descriptorSetLayout);
// POOL // POOL
std::array<VkDescriptorPoolSize, 2> poolSizes; std::array<vk::DescriptorPoolSize, 2> poolSizes;
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSizes[0].type = vk::DescriptorType::eUniformBuffer;
poolSizes[0].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight()); poolSizes[0].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight());
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; poolSizes[1].type = vk::DescriptorType::eCombinedImageSampler;
poolSizes[1].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight()); poolSizes[1].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight());
VkDescriptorPoolCreateInfo poolCI{}; vk::DescriptorPoolCreateInfo poolCI {
poolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; .maxSets = static_cast<uint32_t>(vk.getMaxFramesInFlight()),
poolCI.poolSizeCount = static_cast<uint32_t>(poolSizes.size()); };
poolCI.pPoolSizes = poolSizes.data(); poolCI.setPoolSizes(poolSizes);
poolCI.maxSets = static_cast<uint32_t>(vk.getMaxFramesInFlight());
VkResult result = vkCreateDescriptorPool(vk.getDevice(), &poolCI, nullptr, &descriptorPool); vk::Result result;
if (result != VK_SUCCESS) { std::tie(result, descriptorPool) = vk.getDevice().createDescriptorPool(poolCI);
throw getVkException(result, "Failed to create descriptor pool", "Renderer3D::createDescriptorResources"); if (result != vk::Result::eSuccess) {
} throw getVkException(result, "Failed to create descriptor pool", "Renderer3D::createDescriptorResources");
}
// SETS // SETS
std::vector<VkDescriptorSetLayout> layouts(vk.getMaxFramesInFlight(), descriptorSetLayout); std::vector<vk::DescriptorSetLayout> layouts(vk.getMaxFramesInFlight(), descriptorSetLayout);
VkDescriptorSetAllocateInfo setAI{}; vk::DescriptorSetAllocateInfo setAI {
setAI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; .descriptorPool = descriptorPool,
setAI.descriptorPool = descriptorPool; };
setAI.descriptorSetCount = static_cast<uint32_t>(layouts.size()); setAI.setSetLayouts(layouts);
setAI.pSetLayouts = layouts.data();
descriptorSets.resize(vk.getMaxFramesInFlight()); // TODO is resize needed?
result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, descriptorSets.data()); /* descriptorSets.resize(vk.getMaxFramesInFlight()); */
if (result != VK_SUCCESS) { std::tie(result, descriptorSets) = vk.getDevice().allocateDescriptorSets(setAI);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to create descriptor sets", "Renderer3D::createDescriptorResources"); throw getVkException(result, "Failed to create descriptor sets", "Renderer3D::createDescriptorResources");
} }
// configure sets // configure sets
for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) { for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) {
VkDescriptorBufferInfo bufferI{}; vk::DescriptorBufferInfo bufferI {
bufferI.buffer = uniformBuffers[i]; .buffer = uniformBuffers[i],
bufferI.offset = 0; .offset = 0,
bufferI.range = VK_WHOLE_SIZE; // sizeof(UniformBufferObject); .range = VK_WHOLE_SIZE, // sizeof(UniformBufferObject),
};
VkDescriptorImageInfo imageI{}; vk::DescriptorImageInfo imageI {
imageI.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; .sampler = textureManager.getTextureAtlas().getTextureSampler(),
imageI.imageView = textureManager.getTextureAtlas().getTextureImageView(); .imageView = textureManager.getTextureAtlas().getTextureImageView(),
imageI.sampler = textureManager.getTextureAtlas().getTextureSampler(); .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
};
std::array<VkWriteDescriptorSet, 2> descriptorW{}; std::array<vk::WriteDescriptorSet, 2> descriptorW{};
descriptorW[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorW[0].dstSet = descriptorSets[i]; descriptorW[0].dstSet = descriptorSets[i];
descriptorW[0].dstBinding = bindingUniformBuffer; descriptorW[0].dstBinding = bindingUniformBuffer;
descriptorW[0].dstArrayElement = 0; descriptorW[0].dstArrayElement = 0;
descriptorW[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptorW[0].descriptorType = vk::DescriptorType::eUniformBuffer;
descriptorW[0].descriptorCount = 1; descriptorW[0].setBufferInfo(bufferI);
descriptorW[0].pBufferInfo = &bufferI;
/* descriptorW[0].pImageInfo = nullptr; */ /* descriptorW[0].pImageInfo = nullptr; */
/* descriptorW[0].pTexelBufferView = nullptr; */ /* descriptorW[0].pTexelBufferView = nullptr; */
descriptorW[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorW[1].dstSet = descriptorSets[i]; descriptorW[1].dstSet = descriptorSets[i];
descriptorW[1].dstBinding = bindingCombinedImageSampler; descriptorW[1].dstBinding = bindingCombinedImageSampler;
descriptorW[1].dstArrayElement = 0; descriptorW[1].dstArrayElement = 0;
descriptorW[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorW[1].descriptorType = vk::DescriptorType::eCombinedImageSampler;
descriptorW[1].descriptorCount = 1; descriptorW[1].setImageInfo(imageI);
/* descriptorW[1].pBufferInfo = &bufferI; */
descriptorW[1].pImageInfo = &imageI;
/* descriptorW[1].pTexelBufferView = nullptr; */ /* descriptorW[1].pTexelBufferView = nullptr; */
uint32_t descriptorWriteCount = static_cast<uint32_t>(descriptorW.size()); // write 1, copy 0
uint32_t descriptorCopyCount = 0; vk.getDevice().updateDescriptorSets(descriptorW, nullptr);
vkUpdateDescriptorSets(vk.getDevice(), descriptorWriteCount, descriptorW.data(), descriptorCopyCount, nullptr);
} }
rLog.log0("createDescriptorResources: Created descriptor layouts, pool and sets."); rLog.log0("createDescriptorResources: Created descriptor layouts, pool and sets.");
} }
@ -305,10 +328,10 @@ namespace gz::vk {
void Renderer3D::loadModel() { void Renderer3D::loadModel() {
// load model into VerticesAndIndices struct // load model into VerticesAndIndices struct
rLog.log1("Renderer3D: loadModel: loading model"); rLog.log1("Renderer3D: loadModel: loading model");
vk.loadModel(model); vk.loadModel(settings::MODEL_PATH, model);
// TODO use correct type // TODO use correct type
VkDeviceSize requiredVertexBufferSize = model.vertices.size() * sizeof(Vertex3D); vk::DeviceSize requiredVertexBufferSize = model.vertices.size() * sizeof(Vertex3D);
VkDeviceSize requiredIndexBufferSize = model.indices.size() * sizeof(uint32_t); vk::DeviceSize requiredIndexBufferSize = model.indices.size() * sizeof(uint32_t);
if (requiredVertexBufferSize > vertexBufferSize) { throw VkException("Renderer3D::loadModel: vertex buffer too small"); } if (requiredVertexBufferSize > vertexBufferSize) { throw VkException("Renderer3D::loadModel: vertex buffer too small"); }
if (requiredIndexBufferSize > indexBufferSize) { throw VkException("Renderer3D::loadModel: index buffer too small"); } if (requiredIndexBufferSize > indexBufferSize) { throw VkException("Renderer3D::loadModel: index buffer too small"); }
@ -316,14 +339,18 @@ namespace gz::vk {
rLog.log0("Renderer3D: loadModel: filling vertex buffer"); rLog.log0("Renderer3D: loadModel: filling vertex buffer");
// copy to vertexBuffer // copy to vertexBuffer
// create staging buffer // create staging buffer
VkBuffer stagingBuffer; vk::Buffer stagingBuffer;
MemoryInfo stagingBufferMemory; MemoryInfo stagingBufferMemory;
vk.createBuffer(requiredVertexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); vk.createBuffer(requiredVertexBufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory);
// fill staging buffer // fill staging buffer
void* data; void* data;
vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, requiredVertexBufferSize, NO_FLAGS, &data); vk::Result result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, requiredVertexBufferSize, NO_MEM_FLAGS, &data);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to map staging buffer for vertices", "Renderer3D::loadModel");
}
memcpy(data, model.vertices.data(), requiredVertexBufferSize); memcpy(data, model.vertices.data(), requiredVertexBufferSize);
vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); vk.getDevice().unmapMemory(stagingBufferMemory.memory);
// fill vertex buffer // fill vertex buffer
vk.copyBuffer(stagingBuffer, vertexBuffer, requiredVertexBufferSize); vk.copyBuffer(stagingBuffer, vertexBuffer, requiredVertexBufferSize);
vk.destroyBuffer(stagingBuffer, stagingBufferMemory); vk.destroyBuffer(stagingBuffer, stagingBufferMemory);
@ -331,11 +358,14 @@ namespace gz::vk {
rLog.log0("Renderer3D: loadModel: filling index buffer"); rLog.log0("Renderer3D: loadModel: filling index buffer");
data = nullptr; data = nullptr;
// copy to index buffer // copy to index buffer
vk.createBuffer(requiredIndexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); vk.createBuffer(requiredIndexBufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory);
// fill staging buffer // fill staging buffer
vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, requiredIndexBufferSize, NO_FLAGS, &data); result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, requiredIndexBufferSize, NO_MEM_FLAGS, &data);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to map staging buffer for indices", "Renderer3D::loadModel");
}
memcpy(data, model.indices.data(), requiredIndexBufferSize); memcpy(data, model.indices.data(), requiredIndexBufferSize);
vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); vk.getDevice().unmapMemory(stagingBufferMemory.memory);
// fill index buffer // fill index buffer
vk.copyBuffer(stagingBuffer, indexBuffer, requiredIndexBufferSize); vk.copyBuffer(stagingBuffer, indexBuffer, requiredIndexBufferSize);
vk.destroyBuffer(stagingBuffer, stagingBufferMemory); vk.destroyBuffer(stagingBuffer, stagingBufferMemory);
@ -345,54 +375,50 @@ namespace gz::vk {
// RENDERING // RENDERING
// //
void Renderer3D::recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame) { void Renderer3D::recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame) {
VkCommandBufferBeginInfo commandBufferBI{}; vk::CommandBufferBeginInfo commandBufferBI;
commandBufferBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vk::Result result = commandBuffers[currentFrame].begin(commandBufferBI);
commandBufferBI.flags = 0; if (result != vk::Result::eSuccess) {
commandBufferBI.pInheritanceInfo = nullptr;
VkResult result = vkBeginCommandBuffer(commandBuffers[currentFrame], &commandBufferBI);
if (result != VK_SUCCESS) {
throw getVkException(result, "Failed to begin 3D command buffer", "Renderer3D::recordCommandBuffer"); throw getVkException(result, "Failed to begin 3D command buffer", "Renderer3D::recordCommandBuffer");
} }
VkRenderPassBeginInfo renderPassBI{};
renderPassBI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBI.renderPass = renderPass;
renderPassBI.framebuffer = framebuffers[imageIndex];
renderPassBI.renderArea.offset = { 0, 0 };
renderPassBI.renderArea.extent = vk.getScExtent();
// clear // clear
std::array<VkClearValue, 1> clearValues{}; std::array<vk::ClearValue, 2> clearValues{};
clearValues[0].color = {{1.0f, 0.0f, 0.0f, 1.0f}}; vk::ClearColorValue clearColor{};
/* clearValues[1].depthStencil = {1.0f, 0}; */ clearColor.setFloat32({0.1f, 0.0f, 0.0f, 0.5f});
renderPassBI.clearValueCount = static_cast<uint32_t>(clearValues.size()); clearValues[0].setColor(std::move(clearColor));
renderPassBI.pClearValues = clearValues.data(); clearValues[1].setDepthStencil({1.0f, 0});
vkCmdBeginRenderPass(commandBuffers[currentFrame], &renderPassBI, VK_SUBPASS_CONTENTS_INLINE); vk::RenderPassBeginInfo renderPassBI {
.renderPass = renderPass,
.framebuffer = framebuffers[imageIndex],
.renderArea { .offset = { 0, 0 }, .extent = vk.getScExtent() }
};
renderPassBI.setClearValues(clearValues);
vkCmdBindPipeline(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[PL_3D].pipeline); commandBuffers[currentFrame].beginRenderPass(renderPassBI, vk::SubpassContents::eInline);
VkBuffer vertexBuffers[] = { vertexBuffer };
VkDeviceSize offsets[] = {0}; commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, pipelines[PL_3D].pipeline);
vk::Buffer vertexBuffers[] = { vertexBuffer };
vk::DeviceSize offsets[] = {0};
uint32_t bindingCount = 1; uint32_t bindingCount = 1;
vkCmdBindVertexBuffers(commandBuffers[currentFrame], BINDING, bindingCount, vertexBuffers, offsets); uint32_t firstBinding = 0;
commandBuffers[currentFrame].bindVertexBuffers(firstBinding, bindingCount, vertexBuffers, offsets);
// TODO use correct index type! // TODO use correct index type!
vkCmdBindIndexBuffer(commandBuffers[currentFrame], indexBuffer, NO_OFFSET, VK_INDEX_TYPE_UINT32); commandBuffers[currentFrame].bindIndexBuffer(indexBuffer, NO_OFFSET, vk::IndexType::eUint32);
uint32_t descriptorCount = 1;
uint32_t firstSet = 0; uint32_t firstSet = 0;
uint32_t dynamicOffsetCount = 0; commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelines[PL_3D].layout, firstSet, descriptorSets[currentFrame], {});
uint32_t* dynamicOffsets = nullptr;
vkCmdBindDescriptorSets(commandBuffers[currentFrame], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[PL_3D].layout, firstSet, descriptorCount, &descriptorSets[currentFrame], dynamicOffsetCount, dynamicOffsets);
int instanceCount = 1; int instanceCount = 1;
int firstIndex = 0; int firstIndex = 0;
int firstInstance = 0; int firstInstance = 0;
vkCmdDrawIndexed(commandBuffers[currentFrame], 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);
vkCmdEndRenderPass(commandBuffers[currentFrame]); 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 = vkEndCommandBuffer(commandBuffers[currentFrame]); result = commandBuffers[currentFrame].end();
if (result != VK_SUCCESS) { if (result != vk::Result::eSuccess) {
rLog.error("Failed to record 3D - command buffer", "VkResult:", STR_VK_RESULT(result)); rLog.error("Failed to record 3D - command buffer", "VkResult:", result);
throw getVkException(result, "Failed to record 3D - command buffer", "Renderer3D::recordCommandBuffer"); throw getVkException(result, "Failed to record 3D - command buffer", "Renderer3D::recordCommandBuffer");
} }
vk.submitThisFrame(commandBuffers[currentFrame]); vk.submitThisFrame(commandBuffers[currentFrame]);
@ -401,7 +427,7 @@ namespace gz::vk {
// RENDERING // RENDERING
// //
void Renderer3D::drawFrame(uint32_t imageIndex) { void Renderer3D::drawFrame(uint32_t imageIndex) {
vkResetCommandBuffer(commandBuffers[vk.getCurrentFrame()], NO_FLAGS); commandBuffers[vk.getCurrentFrame()].reset(NO_CMD_RESET_FLAGS);
/* recordCommandBuffer(imageIndex, vk.getCurrentFrame()); */ /* recordCommandBuffer(imageIndex, vk.getCurrentFrame()); */
updateUniformBuffer(); updateUniformBuffer();
recordCommandBuffer(imageIndex, vk.getCurrentFrame()); recordCommandBuffer(imageIndex, vk.getCurrentFrame());
@ -409,13 +435,13 @@ namespace gz::vk {
void Renderer3D::createUniformBuffers() { void Renderer3D::createUniformBuffers() {
VkDeviceSize bufferSize = sizeof(UniformBufferObject); vk::DeviceSize bufferSize = sizeof(UniformBufferObject);
uniformBuffers.resize(vk.getMaxFramesInFlight()); uniformBuffers.resize(vk.getMaxFramesInFlight());
uniformBuffersMemory.resize(vk.getMaxFramesInFlight()); uniformBuffersMemory.resize(vk.getMaxFramesInFlight());
for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) { for (size_t i = 0; i < vk.getMaxFramesInFlight(); i++) {
vk.createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]); vk.createBuffer(bufferSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, uniformBuffers[i], uniformBuffersMemory[i]);
} }
} }
@ -436,9 +462,12 @@ namespace gz::vk {
/* ubo.projection[1][1] *= -1; // y coordinate inverted in opengl */ /* ubo.projection[1][1] *= -1; // y coordinate inverted in opengl */
MemoryInfo& uniformBufferMI = uniformBuffersMemory[vk.getCurrentFrame()]; MemoryInfo& uniformBufferMI = uniformBuffersMemory[vk.getCurrentFrame()];
void* data; void* data;
vkMapMemory(vk.getDevice(), uniformBufferMI.memory, uniformBufferMI.offset, sizeof(ubo), NO_FLAGS, &data); vk::Result result = vk.getDevice().mapMemory(uniformBufferMI.memory, uniformBufferMI.offset, sizeof(ubo), NO_MEM_FLAGS, &data);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to map staging buffer", "Renderer3D::updateUniformBuffer");
}
memcpy(data, &ubo, sizeof(ubo)); memcpy(data, &ubo, sizeof(ubo));
vkUnmapMemory(vk.getDevice(), uniformBufferMI.memory); vk.getDevice().unmapMemory(uniformBufferMI.memory);
} }
@ -446,4 +475,4 @@ namespace gz::vk {
} // namespace gz::vk } // namespace gz::vlk

View File

@ -5,7 +5,7 @@
#include "vulkan_allocator.hpp" #include "vulkan_allocator.hpp"
#include "vulkan_util.hpp" #include "vulkan_util.hpp"
namespace gz::vk { namespace gz::vlk {
struct UniformBufferObject { struct UniformBufferObject {
alignas(16) glm::mat4 model; alignas(16) glm::mat4 model;
alignas(16) glm::mat4 view; alignas(16) glm::mat4 view;
@ -34,7 +34,7 @@ namespace gz::vk {
/// @} /// @}
private: private:
void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame); void recordCommandBuffer(uint32_t imageIndex, uint32_t currentFrame);
std::vector<VkBuffer> uniformBuffers; std::vector<vk::Buffer> uniformBuffers;
std::vector<MemoryInfo> uniformBuffersMemory; std::vector<MemoryInfo> uniformBuffersMemory;
void createUniformBuffers(); void createUniformBuffers();
void updateUniformBuffer(); void updateUniformBuffer();
@ -45,24 +45,36 @@ namespace gz::vk {
* The images are used as render targets. After rendering, the current image gets blitted onto the current swap chain image. * The images are used as render targets. After rendering, the current image gets blitted onto the current swap chain image.
*/ */
/// @{ /// @{
std::vector<VkImage> images; std::vector<vk::Image> images;
std::vector<MemoryInfo> imageMemory; std::vector<MemoryInfo> imageMemory;
std::vector<VkImageView> imageViews; std::vector<vk::ImageView> imageViews;
/** /**
* @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images * @brief Creates the images (on imageMemory) and imageViews with the format of the VulkanInstance::swapChain images
*/ */
void createImages(); void createImages();
/// @} /// @}
/**
* @name Depth
*/
/// @{
vk::Image depthImage;
MemoryInfo depthImageMemory;
vk::ImageView depthImageView;
/**
* @brief Create depth image and view with a @ref VulkanInstance::getDepthFormat() "depth format"
*/
void createDepthImage();
/// @}
/** /**
* @name Render pass * @name Render pass
* @details * @details
* Attachments: * Attachments:
* - color blend: * - color blend:
* - loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR * - loadOp = vk::AttachmentLoadOp::eClear
* - storeOp = VK_ATTACHMENT_STORE_OP_STORE * - storeOp = vk::AttachmentStoreOp::eStore
* - initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL * - initialLayout = vk::ImageLayout::eColorAttachmentOptimal
* - finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL * - finalLayout = vk::ImageLayout::eColorAttachmentOptimal
* - stencil load/store = dont care * - stencil load/store = dont care
*/ */
/// @{ /// @{
@ -70,10 +82,10 @@ namespace gz::vk {
* @brief Create a render pass * @brief Create a render pass
*/ */
void createRenderPass(); void createRenderPass();
VkRenderPass renderPass; vk::RenderPass renderPass;
/// @} /// @}
std::vector<VkFramebuffer> framebuffers; std::vector<vk::Framebuffer> framebuffers;
// PIPELINE // PIPELINE
PipelineContainer pipelines; PipelineContainer pipelines;
@ -84,9 +96,9 @@ namespace gz::vk {
* -# Combined Image Sampler (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) * -# Combined Image Sampler (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
*/ */
/// @{ /// @{
VkDescriptorPool descriptorPool; vk::DescriptorPool descriptorPool;
VkDescriptorSetLayout descriptorSetLayout; vk::DescriptorSetLayout descriptorSetLayout;
std::vector<VkDescriptorSet> descriptorSets; std::vector<vk::DescriptorSet> descriptorSets;
/** /**
* @brief Create a descriptor layout binding for the MVP uniform buffer object * @brief Create a descriptor layout binding for the MVP uniform buffer object
* @details Create a desciptor set layout with bindings for * @details Create a desciptor set layout with bindings for
@ -116,10 +128,11 @@ namespace gz::vk {
/** /**
* @brief Sets up resources that depend on the swap chain or its attributes * @brief Sets up resources that depend on the swap chain or its attributes
* @details * @details
* Initializes up: * Initializes:
* - images, imageMemory, imageViews * - @ref createRenderPass() "render pass"
* - framebuffers * - @ref createImages() "images and imageViews"
* - render pass * - @ref createDepthImage() "depth image and view"
* - @ref VulkanInstance::createFramebuffers() "framebuffers"
* - pipeline * - pipeline
*/ */
void initSwapChainDependantResources(); void initSwapChainDependantResources();

View File

@ -1,16 +0,0 @@
#version 450
#extension GL_EXT_debug_printf : enable
layout(binding = 1) uniform sampler2D textureSampler;
layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTextureCoordinate;
layout(location = 0) out vec4 outColor;
void main() {
/* outColor = vec4(fragColor, 1.0); */
/* debugPrintfEXT("outColor %v3f", fragColor); */
outColor = vec4(fragTextureCoordinate, 0.0, 1.0);
/* outColor = vec4(fragColor * texture(textureSampler, fragTextureCoordinate).rgb, 1.0); */
}

View File

@ -1,25 +0,0 @@
#version 450
#extension GL_EXT_debug_printf : enable
layout(binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
} ubo;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTextureCoordinate;
layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTextureCoordinate;
void main() {
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
/* gl_Position = vec4(inPosition, 1.0); */
/* debugPrintfEXT("inPosition %v3f, inColor %v3f", inPosition, inColor); */
fragColor = inColor;
fragTextureCoordinate = inTextureCoordinate;
}

View File

@ -1,17 +0,0 @@
#version 450
#extension GL_EXT_debug_printf : enable
layout(binding = 0) uniform sampler2D textureSampler;
layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTextureCoordinate;
layout(location = 0) out vec4 outColor;
void main() {
/* outColor = vec4(fragColor, 1.0); */
/* outColor = vec4(fragTextureCoordinate, 0.0, 1.0); */
/* outColor = vec4(fragColor * texture(textureSampler, fragTextureCoordinate).rgb, 1.0); */
outColor = texture(textureSampler, fragTextureCoordinate);
/* debugPrintfEXT("outColor %v3f", outColor); */
}

View File

@ -1,25 +0,0 @@
#version 450
#extension GL_EXT_debug_printf : enable
/* layout(binding = 0) uniform UniformBufferObject { */
/* mat4 model; */
/* mat4 view; */
/* mat4 proj; */
/* } ubo; */
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTextureCoordinate;
layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTextureCoordinate;
void main() {
/* gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); */
gl_Position = vec4(inPosition, 0.0, 1.0);
/* debugPrintfEXT("inPosition %v2f, inColor %v3f", inPosition, inColor); */
fragColor = inColor;
fragTextureCoordinate = inTextureCoordinate;
}

View File

@ -2,7 +2,7 @@
#include "texture_manager.hpp" #include "texture_manager.hpp"
namespace gz::vk { namespace gz::vlk {
Rectangle::Rectangle(float top, float left, uint32_t width, uint32_t height, glm::vec3 color, std::string&& texture) Rectangle::Rectangle(float top, float left, uint32_t width, uint32_t height, glm::vec3 color, std::string&& texture)
: top(top), left(left), width(width), height(height), color(color) : top(top), left(left), width(width), height(height), color(color)
{ {
@ -55,4 +55,4 @@ namespace gz::vk {
} }
} // namespace gz::vk } // namespace gz::vlk

View File

@ -3,7 +3,7 @@
#include "vertex.hpp" #include "vertex.hpp"
#include <cstdint> #include <cstdint>
namespace gz::vk { namespace gz::vlk {
// defined in texture_manager.hpp // defined in texture_manager.hpp
class TextureManager; class TextureManager;
class Shape { class Shape {
@ -46,4 +46,4 @@ namespace gz::vk {
glm::vec3 color; glm::vec3 color;
void generateVertices(); void generateVertices();
}; };
} // namespace gz::vk } // namespace gz::vlk

View File

@ -1,9 +1,9 @@
#include "exceptions.hpp" #include "exceptions.hpp"
#include "vk_enum_string.h" #include "vulkan_util.hpp"
namespace gz { namespace gz {
VkException getVkException(VkResult result, std::string&& what, std::string&& functionName) { VkException getVkException(vk::Result result, std::string&& what, std::string&& functionName) {
std::string whatStr; std::string whatStr;
if (!functionName.empty()) { if (!functionName.empty()) {
whatStr += "Error in function: " + functionName + ": "; whatStr += "Error in function: " + functionName + ": ";
@ -15,7 +15,7 @@ namespace gz {
whatStr += what + ": "; whatStr += what + ": ";
} }
whatStr += "VkResult="; whatStr += "VkResult=";
whatStr += STR_VK_RESULT(result); whatStr += ::toString(result);
return VkException(whatStr); return VkException(whatStr);
} }
} }

View File

@ -2,7 +2,8 @@
#include <gz-util/exceptions.hpp> #include <gz-util/exceptions.hpp>
#include <vulkan/vulkan_core.h> #define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include <exception> #include <exception>
#include <string> #include <string>
@ -31,7 +32,8 @@ namespace gz {
/** /**
* @brief Return a VkException with a formatted string * @brief Return a VkException with a formatted string
* @todo Return different Exceptions depending in result or make this a constructor of VkException
*/ */
VkException getVkException(VkResult result, std::string&& what="", std::string&& functionName=""); VkException getVkException(vk::Result result, std::string&& what="", std::string&& functionName="");
} }

View File

@ -12,10 +12,10 @@
#include <gz-util/util/string_concepts.hpp> #include <gz-util/util/string_concepts.hpp>
#include <gz-util/util/string_conversion.hpp> #include <gz-util/util/string_conversion.hpp>
#include <ratio> #include <ratio>
#include <vulkan/vulkan_core.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
namespace gz::vk { namespace gz::vlk {
std::string TextureImageArea::toString() const { std::string TextureImageArea::toString() const {
return "<(" + gz::toString(x) + "," + gz::toString(y) + "), (" + gz::toString(width) + "x" + gz::toString(height) + ")>"; return "<(" + gz::toString(x) + "," + gz::toString(y) + "), (" + gz::toString(width) + "x" + gz::toString(height) + ")>";
} }
@ -29,12 +29,13 @@ TextureAtlas::TextureAtlas(VulkanInstance& instance, uint16_t slotWidth, uint16_
slotCountX(slotCountX), slotCountY(slotCountY) slotCountX(slotCountX), slotCountY(slotCountY)
{ {
#ifdef LOG_LEVEL_0 #ifdef LOG_LEVEL_0
LogCreateInfo logCI{}; LogCreateInfo logCI{
logCI.logfile = "textureAtlas.log"; .logfile = "textureAtlas.log",
logCI.storeLog = false; .storeLog = false,
logCI.prefix = "TextureAtlas (" + gz::toString(slotCountX) + "x" + gz::toString(slotCountY) + ")X(" + gz::toString(slotWidth) + "x" + gz::toString(slotHeight) + ")"; .prefix = "TextureAtlas (" + gz::toString(slotCountX) + "x" + gz::toString(slotCountY) + ")X(" + gz::toString(slotWidth) + "x" + gz::toString(slotHeight) + ")",
logCI.prefixColor = Color::GREEN; .prefixColor = Color::GREEN,
logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR,
};
tLog = Log(std::move(logCI)); tLog = Log(std::move(logCI));
#endif #endif
@ -59,23 +60,24 @@ void TextureAtlas::cleanup() {
void TextureAtlas::createImageResources() { void TextureAtlas::createImageResources() {
vk.createImage(slotWidth * slotCountX, slotHeight * slotCountY, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_LINEAR, vk.createImage(slotWidth * slotCountX, slotHeight * slotCountY, vk::Format::eR8G8B8A8Srgb, vk::ImageTiling::eLinear,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vk::MemoryPropertyFlagBits::eDeviceLocal,
textureImage, textureImageMemory); textureImage, textureImageMemory);
VkCommandBuffer cmdBuffer = vk.beginSingleTimeCommands(POOL_GRAPHICS); vk::CommandBuffer cmdBuffer = vk.beginSingleTimeCommands(POOL_GRAPHICS);
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cmdBuffer); vk.transitionImageLayout(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, &cmdBuffer);
VkImageSubresourceRange subresourceRange{}; vk::ImageSubresourceRange subresourceRange {
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; .aspectMask = vk::ImageAspectFlagBits::eColor,
subresourceRange.baseMipLevel = 0; .baseMipLevel = 0,
subresourceRange.levelCount = 1; .levelCount = 1,
subresourceRange.baseArrayLayer = 0; .baseArrayLayer = 0,
subresourceRange.layerCount = 1; .layerCount = 1,
vkCmdClearColorImage(cmdBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &missingTextureColor, 1, &subresourceRange); };
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &cmdBuffer); cmdBuffer.clearColorImage(textureImage, vk::ImageLayout::eTransferDstOptimal, &settings::missingTextureColor, 1, &subresourceRange);
vk.transitionImageLayout(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal, &cmdBuffer);
vk.endSingleTimeCommands(cmdBuffer, POOL_GRAPHICS); vk.endSingleTimeCommands(cmdBuffer, POOL_GRAPHICS);
vk.createImageView(VK_FORMAT_R8G8B8A8_SRGB, textureImage, textureImageView, VK_IMAGE_ASPECT_COLOR_BIT); vk.createImageView(vk::Format::eR8G8B8A8Srgb, textureImage, textureImageView, vk::ImageAspectFlagBits::eColor);
vk.createTextureSampler(textureSampler); vk.createTextureSampler(textureSampler);
} }
@ -161,22 +163,26 @@ std::pair<glm::vec2, glm::vec2> TextureAtlas::addTexture(uint8_t* pixels, uint16
void TextureAtlas::blitTextureOnImage(uint8_t* pixels, uint16_t slotX, uint16_t slotY, uint16_t textureWidth, uint16_t textureHeight) { void TextureAtlas::blitTextureOnImage(uint8_t* pixels, uint16_t slotX, uint16_t slotY, uint16_t textureWidth, uint16_t textureHeight) {
constexpr size_t BYTES_PER_PIXEL = 4; constexpr size_t BYTES_PER_PIXEL = 4;
VkDeviceSize imageSize = textureWidth * textureHeight * BYTES_PER_PIXEL; vk::DeviceSize imageSize = textureWidth * textureHeight * BYTES_PER_PIXEL;
VkBuffer stagingBuffer; vk::Buffer stagingBuffer;
MemoryInfo stagingBufferMemory; MemoryInfo stagingBufferMemory;
vk.createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, vk.createBuffer(imageSize, vk::BufferUsageFlagBits::eTransferSrc,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent,
stagingBuffer, stagingBufferMemory); stagingBuffer, stagingBufferMemory);
void* data; void* data;
vkMapMemory(vk.getDevice(), stagingBufferMemory.memory, stagingBufferMemory.offset, imageSize, NO_FLAGS, &data); vk::Result result = vk.getDevice().mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, imageSize, vk::MemoryMapFlags(), &data);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to map staging buffer", "TextureAtlas::blitTextureOnImage");
}
memcpy(data, pixels, static_cast<size_t>(imageSize)); memcpy(data, pixels, static_cast<size_t>(imageSize));
vkUnmapMemory(vk.getDevice(), stagingBufferMemory.memory); vk.getDevice().unmapMemory(stagingBufferMemory.memory);
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); vk.transitionImageLayout(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eTransferDstOptimal);
vk.copyBufferToImage(stagingBuffer, textureImage, vk.copyBufferToImage(stagingBuffer, textureImage,
static_cast<int32_t>(slotWidth * slotX), static_cast<int32_t>(slotHeight * slotY), // offset static_cast<int32_t>(slotWidth * slotX), static_cast<int32_t>(slotHeight * slotY), // offset
static_cast<uint32_t>(textureWidth), static_cast<uint32_t>(textureHeight)); // dimensions static_cast<uint32_t>(textureWidth), static_cast<uint32_t>(textureHeight)); // dimensions
vk.transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); vk.transitionImageLayout(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
vk.destroyBuffer(stagingBuffer, stagingBufferMemory); vk.destroyBuffer(stagingBuffer, stagingBufferMemory);
} }

View File

@ -3,7 +3,8 @@
#include "vulkan_allocator.hpp" #include "vulkan_allocator.hpp"
#include <gz-util/log.hpp> #include <gz-util/log.hpp>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <vulkan/vulkan_core.h> #define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include <vector> #include <vector>
#include <string> #include <string>
@ -14,7 +15,7 @@
#include <gz-util/log.hpp> #include <gz-util/log.hpp>
#endif #endif
namespace gz::vk { namespace gz::vlk {
/** /**
* @brief Describes an area in the textureImage that is not in use * @brief Describes an area in the textureImage that is not in use
*/ */
@ -61,8 +62,8 @@ namespace gz::vk {
* @throws Exception when there is no space in the atlas to add the texture * @throws Exception when there is no space in the atlas to add the texture
*/ */
std::pair<glm::vec2, glm::vec2> addTexture(uint8_t* pixels, uint16_t textureWidth, uint16_t textureHeight); std::pair<glm::vec2, glm::vec2> addTexture(uint8_t* pixels, uint16_t textureWidth, uint16_t textureHeight);
const VkImageView& getTextureImageView() const { return textureImageView; } const vk::ImageView& getTextureImageView() const { return textureImageView; }
const VkSampler& getTextureSampler() const { return textureSampler; } const vk::Sampler& getTextureSampler() const { return textureSampler; }
std::string toString() const; std::string toString() const;
@ -81,10 +82,10 @@ namespace gz::vk {
* the textureImage is created with missingTextureColor and then transitioned to SHADER_READ_ONLY_OPTIMAL layout. * the textureImage is created with missingTextureColor and then transitioned to SHADER_READ_ONLY_OPTIMAL layout.
*/ */
void createImageResources(); void createImageResources();
VkImage textureImage; vk::Image textureImage;
MemoryInfo textureImageMemory; MemoryInfo textureImageMemory;
VkImageView textureImageView; vk::ImageView textureImageView;
VkSampler textureSampler; vk::Sampler textureSampler;
std::set<TextureImageArea, decltype(freeAreaCmp)> freeAreas; std::set<TextureImageArea, decltype(freeAreaCmp)> freeAreas;
/** /**
@ -103,4 +104,4 @@ namespace gz::vk {
Log tLog; Log tLog;
#endif #endif
}; };
} // namespace gz::vk } // namespace gz::vlk

View File

@ -3,22 +3,22 @@
#include "vulkan_instance.hpp" #include "vulkan_instance.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <vulkan/vulkan_core.h>
namespace gz::vk { namespace gz::vlk {
TextureManager::TextureManager(VulkanInstance& instance) TextureManager::TextureManager(VulkanInstance& instance)
: vk(instance) : vk(instance)
{ {
LogCreateInfo logCI{}; LogCreateInfo logCI{
logCI.logfile = "textureManager.log"; .logfile = "textureManager.log",
logCI.storeLog = false; .storeLog = false,
logCI.prefix = "Texture"; .prefix = "Texture",
logCI.prefixColor = Color::GREEN; .prefixColor = Color::GREEN,
logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR,
};
tLog = Log(std::move(logCI)); tLog = Log(std::move(logCI));
vk.registerCleanupCallback(std::bind(&TextureManager::cleanup, this)); vk.registerCleanupCallback(std::bind(&TextureManager::cleanup, this));
atlases.insert({ 0, TextureAtlas(vk, 24, 24, 24, 24) }); atlases.emplace_back(TextureAtlas(vk, 24, 24, 24, 24));
createDescriptorSetLayout(); createDescriptorSetLayout();
createDescriptorPool(); createDescriptorPool();
createDescriptorSet(); createDescriptorSet();
@ -30,12 +30,10 @@ namespace gz::vk {
void TextureManager::cleanup() { void TextureManager::cleanup() {
tLog.log0("cleanup: cleaning up"); tLog.log0("cleanup: cleaning up");
/* vkFreeDescriptorSets(vk.getDevice(), descriptorPool, 1, &descriptorSet); */ vk.getDevice().destroyDescriptorSetLayout(descriptorSetLayout, NO_ALLOC);
vkDestroyDescriptorSetLayout(vk.getDevice(), descriptorSetLayout, NO_ALLOC); vk.getDevice().destroyDescriptorPool(descriptorPool, NO_ALLOC);
vkDestroyDescriptorPool(vk.getDevice(), descriptorPool, NO_ALLOC); for (auto& atlas : atlases) {
for (auto& [i, atlas] : atlases) {
atlas.cleanup(); atlas.cleanup();
} }
} }
@ -46,8 +44,6 @@ namespace gz::vk {
} }
TextureInfo& texI = textureInfos[textureName]; TextureInfo& texI = textureInfos[textureName];
tLog.log0("getTexCoords", texCoords, "textureInfo: topleft", texI.texCoordTopLeft, "botright", texI.texCoordBottomRight); tLog.log0("getTexCoords", texCoords, "textureInfo: topleft", texI.texCoordTopLeft, "botright", texI.texCoordBottomRight);
/* texCoords.x = texI.texCoordTopLeft.x + texCoords.x * (texI.texCoordBottomRight.x - texI.texCoordTopLeft.x); */
/* texCoords.y = texI.texCoordTopLeft.y + texCoords.y * (texI.texCoordBottomRight.y - texI.texCoordTopLeft.y); */
texCoords = texI.texCoordTopLeft + texCoords * (texI.texCoordBottomRight - texI.texCoordTopLeft); texCoords = texI.texCoordTopLeft + texCoords * (texI.texCoordBottomRight - texI.texCoordTopLeft);
} }
@ -60,11 +56,12 @@ namespace gz::vk {
} }
TextureInfo& texI = textureInfos[textureName]; TextureInfo& texI = textureInfos[textureName];
texI.atlas = 0; texI.atlas = 0;
// TODO
auto texCoords = atlases.at(0).addTexture(pixels, textureWidth, textureHeight); auto texCoords = atlases.at(0).addTexture(pixels, textureWidth, textureHeight);
stbi_image_free(pixels); stbi_image_free(pixels);
tLog.log0("TextureManager::loadTextureFromFile: TexCoords of new image:", texCoords.first, texCoords.second); tLog.log0("TextureManager::loadTextureFromFile: TexCoords of new image:", texCoords.first, texCoords.second);
texI.texCoordTopLeft = std::move(texCoords.first); texI.texCoordTopLeft = std::move(texCoords.first),
texI.texCoordBottomRight = std::move(texCoords.second); texI.texCoordBottomRight = std::move(texCoords.second),
tLog.log0("TextureManager::loadTextureFromFile: After loading:", atlases.at(0)); tLog.log0("TextureManager::loadTextureFromFile: After loading:", atlases.at(0));
} }
@ -74,20 +71,20 @@ namespace gz::vk {
// //
void TextureManager::createDescriptorSetLayout() { void TextureManager::createDescriptorSetLayout() {
// combined image sampler // combined image sampler
VkDescriptorSetLayoutBinding samplerLayoutBinding{}; std::vector<vk::DescriptorSetLayoutBinding> samplerLayoutBindings(atlases.size(), {
samplerLayoutBinding.binding = 0; .binding = 0,
samplerLayoutBinding.descriptorCount = 1; .descriptorType = vk::DescriptorType::eCombinedImageSampler,
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; .descriptorCount = 1,
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; .stageFlags = vk::ShaderStageFlagBits::eFragment,
/* samplerLayoutBinding.pImmutableSamplers = nullptr; */ /* .pImmutableSamplers = nullptr, */
}
);
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{}; vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCI;
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; descriptorSetLayoutCI.setBindings(samplerLayoutBindings);
descriptorSetLayoutCI.bindingCount = 1;
descriptorSetLayoutCI.pBindings = &samplerLayoutBinding;
VkResult result = vkCreateDescriptorSetLayout(vk.getDevice(), &descriptorSetLayoutCI, nullptr, &descriptorSetLayout); vk::Result result = vk.getDevice().createDescriptorSetLayout(&descriptorSetLayoutCI, nullptr, &descriptorSetLayout);
if (result != VK_SUCCESS) { if (result != vk::Result::eSuccess) {
throw getVkException(result, "Could not create descriptorSetLayout", "TextureManager::createDescriptorSetLayout"); throw getVkException(result, "Could not create descriptorSetLayout", "TextureManager::createDescriptorSetLayout");
} }
/* vLog("createDescriptorSetLayout: Created descriptor set layout."); */ /* vLog("createDescriptorSetLayout: Created descriptor set layout."); */
@ -95,64 +92,56 @@ void TextureManager::createDescriptorSetLayout() {
void TextureManager::createDescriptorPool() { void TextureManager::createDescriptorPool() {
std::array<VkDescriptorPoolSize, 1> poolSizes; std::vector<vk::DescriptorPoolSize> poolSizes {
/* poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; */ vk::DescriptorPoolSize {
/* poolSizes[0].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight()); */ .type = vk::DescriptorType::eCombinedImageSampler,
poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; .descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight())
poolSizes[0].descriptorCount = static_cast<uint32_t>(vk.getMaxFramesInFlight()); }
};
VkDescriptorPoolCreateInfo poolCI{}; vk::DescriptorPoolCreateInfo poolCI { .maxSets = 1 };
poolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; poolCI.setPoolSizes(poolSizes);
poolCI.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
poolCI.pPoolSizes = poolSizes.data(); vk::Result result;
poolCI.maxSets = 1; std::tie(result, descriptorPool) = vk.getDevice().createDescriptorPool(poolCI);
VkResult result = vkCreateDescriptorPool(vk.getDevice(), &poolCI, nullptr, &descriptorPool); if (result != vk::Result::eSuccess) {
if (result != VK_SUCCESS) { throw getVkException(result, "Failed to create descriptor pool", "TextureManager::createDescriptorPool");
throw getVkException(result, "Failed to create descriptor pool", "TextureManager::createDescriptorPool"); }
}
/* vLog("createDescriptorPool: Created descriptor pool."); */ /* vLog("createDescriptorPool: Created descriptor pool."); */
} }
void TextureManager::createDescriptorSet() { void TextureManager::createDescriptorSet() {
/* std::vector<VkDescriptorSetLayout> layouts(vk.getMaxFramesInFlight(), descriptorSetLayout); */ vk::DescriptorSetAllocateInfo setAI {
VkDescriptorSetAllocateInfo setAI{}; .descriptorPool = descriptorPool,
setAI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; };
setAI.descriptorPool = descriptorPool; setAI.setSetLayouts(descriptorSetLayout);
/* setAI.descriptorSetCount = static_cast<uint32_t>(vk.getMaxFramesInFlight()); */
/* setAI.pSetLayouts = layouts.data(); */
setAI.descriptorSetCount = 1;
setAI.pSetLayouts = &descriptorSetLayout;
/* descriptorSets.resize(vk.getMaxFramesInFlight()); */ auto [result, descriptorSetV] = vk.getDevice().allocateDescriptorSets(setAI);
/* VkResult result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, descriptorSets.data()); */ descriptorSet = descriptorSetV.front();
VkResult result = vkAllocateDescriptorSets(vk.getDevice(), &setAI, &descriptorSet); if (result != vk::Result::eSuccess) {
if (result != VK_SUCCESS) {
throw getVkException(result, "Failed to create descriptor set", "TextureManager::createDescriptorPool"); throw getVkException(result, "Failed to create descriptor set", "TextureManager::createDescriptorPool");
} }
// configure sets // configure sets
std::vector<VkDescriptorImageInfo> imageInfos; std::vector<vk::DescriptorImageInfo> imageInfos;
for (auto it = atlases.cbegin(); it != atlases.cend(); it++) { for (auto it = atlases.cbegin(); it != atlases.cend(); it++) {
imageInfos.emplace_back(); imageInfos.emplace_back();
imageInfos.back().imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfos.back().imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
imageInfos.back().imageView = it->second.getTextureImageView(); imageInfos.back().imageView = it->getTextureImageView();
imageInfos.back().sampler = it->second.getTextureSampler(); imageInfos.back().sampler = it->getTextureSampler();
} }
std::array<VkWriteDescriptorSet, 1> descriptorW{}; vk::WriteDescriptorSet descriptorW {
descriptorW[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; .dstSet = descriptorSet,
descriptorW[0].dstSet = descriptorSet; .dstBinding = 0,
descriptorW[0].dstBinding = 0; .dstArrayElement = 0,
descriptorW[0].dstArrayElement = 0; .descriptorType = vk::DescriptorType::eCombinedImageSampler,
descriptorW[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; };
descriptorW[0].descriptorCount = static_cast<uint32_t>(imageInfos.size()); descriptorW.setImageInfo(imageInfos);
descriptorW[0].pImageInfo = imageInfos.data();
uint32_t descriptorWriteCount = static_cast<uint32_t>(descriptorW.size()); // 1 write, no copies
uint32_t descriptorCopyCount = 0; vk.getDevice().updateDescriptorSets(descriptorW, nullptr);
vkUpdateDescriptorSets(vk.getDevice(), descriptorWriteCount, descriptorW.data(), descriptorCopyCount, nullptr); tLog.log0("createDescriptorSets: Created descriptor sets.");
/* } */
/* vLog("createDescriptorSets: Created descriptor sets."); */
} }
} // namespace gz::vk } // namespace gz::vlk

View File

@ -10,7 +10,7 @@
#include <unordered_map> #include <unordered_map>
namespace gz::vk { namespace gz::vlk {
struct TextureInfo { struct TextureInfo {
uint32_t atlas; uint32_t atlas;
glm::vec2 texCoordTopLeft; glm::vec2 texCoordTopLeft;
@ -28,30 +28,35 @@ namespace gz::vk {
*/ */
TextureManager(VulkanInstance& instance); TextureManager(VulkanInstance& instance);
void getTexCoords(const std::string& textureName, glm::vec2& texCoords); void getTexCoords(const std::string& textureName, glm::vec2& texCoords);
const VkDescriptorSet& getDescriptorSet() const { return descriptorSet; } const vk::DescriptorSet& getDescriptorSet() const { return descriptorSet; }
const VkDescriptorSetLayout& getDescriptorSetLayout() const { return descriptorSetLayout; } const vk::DescriptorSetLayout& getDescriptorSetLayout() const { return descriptorSetLayout; }
// TODO // TODO
/// @todo take texture as argument /// @todo take texture as argument
const TextureAtlas& getTextureAtlas() const { return atlases.at(0); }; const TextureAtlas& getTextureAtlas() const { return atlases.at(0); }
uint32_t getAtlasCount() const { return static_cast<uint32_t>(atlases.size()); }
private: private:
void cleanup(); void cleanup();
void loadTextureFromFile(const std::string& textureName); void loadTextureFromFile(const std::string& textureName);
std::unordered_map<uint32_t, TextureAtlas> atlases; // TODO index currently has no meaning
std::vector<TextureAtlas> atlases;
/**
* @brief Contains textureName : TextureInfo pairs
*/
util::unordered_string_map<TextureInfo> textureInfos; util::unordered_string_map<TextureInfo> textureInfos;
VulkanInstance& vk; VulkanInstance& vk;
Log tLog; Log tLog;
/** /**
* @name Create desciptors * @name Create desciptors
* @details These functions create a desciptor with bindings for * @details These functions create a desciptor with bindings for
* -# Combined Image Sampler (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) at binding 0 * -# Array of combined image samplers (DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) at binding 0. Array length is atlas count
* @{ * @{
*/ */
VkDescriptorSetLayout descriptorSetLayout; vk::DescriptorSetLayout descriptorSetLayout;
VkDescriptorPool descriptorPool; vk::DescriptorPool descriptorPool;
VkDescriptorSet descriptorSet; vk::DescriptorSet descriptorSet;
/* std::vector<VkDescriptorSet> descriptorSets; */ /* std::vector<vk::DescriptorSet> descriptorSets; */
/** /**
* @brief Create a descriptor set layout * @brief Create a descriptor set layout
* @details * @details
@ -69,4 +74,4 @@ namespace gz::vk {
}; };
} // namespace gz::vk } // namespace gz::vlk

View File

@ -1,9 +1,13 @@
#include "vulkan_util.hpp" #include "vulkan_util.hpp"
#include <iostream> #include <iostream>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_enums.hpp>
#include <vulkan/vulkan_structs.hpp>
#define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
namespace gz::vk { namespace gz::vlk {
// //
// CONVENIENCE // CONVENIENCE
// //
@ -16,6 +20,9 @@ namespace gz::vk {
f11.pNext = &f12; f11.pNext = &f12;
f12.pNext = &f13; f12.pNext = &f13;
} }
/* static_assert(sizeof(VkStructureType) != sizeof(vk::StructureType), "Objects do not have same size"); */
/* static_assert(sizeof(VkPhysicalDeviceFeatures) != sizeof(vk::PhysicalDeviceFeatures), "Objects do not have same size"); */
bool PhysicalDeviceFeatures::requiredFeaturesAvailable(const PhysicalDeviceFeatures& requiredFeatures) const { bool PhysicalDeviceFeatures::requiredFeaturesAvailable(const PhysicalDeviceFeatures& requiredFeatures) const {
// iterate over all the features in the structs // iterate over all the features in the structs
// VkPhysicalDeviceFeatures2 // VkPhysicalDeviceFeatures2
@ -68,53 +75,47 @@ namespace gz::vk {
return true; return true;
} }
void PipelineContainer::erase(const PipelineT& key, const VkDevice& device, const VkAllocationCallbacks* pAllocator) { void PipelineContainer::erase(const PipelineT& key, const vk::Device& device, const vk::AllocationCallbacks* pAllocator) {
vkDestroyPipeline(device, pipelines[key].pipeline, pAllocator); device.destroyPipeline(pipelines[key].pipeline, pAllocator);
vkDestroyPipelineLayout(device, pipelines[key].layout, pAllocator); device.destroyPipelineLayout(pipelines[key].layout, pAllocator);
pipelines.erase(pipelines.find(key)); pipelines.erase(pipelines.find(key));
} }
PipelineContainer::iterator PipelineContainer::erase(const PipelineContainer::iterator& it, const VkDevice& device, const VkAllocationCallbacks* pAllocator) { PipelineContainer::iterator PipelineContainer::erase(const PipelineContainer::iterator& it, const vk::Device& device, const vk::AllocationCallbacks* pAllocator) {
vkDestroyPipeline(device, it->second.pipeline, pAllocator); device.destroyPipeline(it->second.pipeline, pAllocator);
vkDestroyPipelineLayout(device, it->second.layout, pAllocator); device.destroyPipelineLayout(it->second.layout, pAllocator);
return pipelines.erase(it); return pipelines.erase(it);
} }
void PipelineContainer::destroy(const VkDevice& device, const VkAllocationCallbacks* pAllocator) { void PipelineContainer::destroy(const vk::Device& device, const vk::AllocationCallbacks* pAllocator) {
auto it = pipelines.begin(); while (it != pipelines.end()) { auto it = pipelines.begin(); while (it != pipelines.end()) {
it = erase(it, device); it = erase(it, device);
} }
} }
VkDependencyInfo getDepInfo(const VkImageMemoryBarrier2& barrier) { vk::DependencyInfo getDepInfo(const vk::ImageMemoryBarrier2& barrier) {
VkDependencyInfo depI{}; vk::DependencyInfo depI {
depI.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; .imageMemoryBarrierCount = 1,
depI.imageMemoryBarrierCount = 1; .pImageMemoryBarriers = &barrier,
depI.pImageMemoryBarriers = &barrier; };
return depI; return depI;
} }
void getBufferMemoryRequirements(const VkDevice& device, const VkBuffer& buffer, VkBufferMemoryRequirementsInfo2& bufMemReq, VkMemoryRequirements2& memReq) { /* void getBufferMemoryRequirements(const vk::Device& device, const vk::Buffer& buffer, vk::BufferMemoryRequirementsInfo2& bufMemReq, vk::MemoryRequirements2& memReq) { */
bufMemReq.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2; /* bufMemReq.pNext = nullptr; */
bufMemReq.pNext = nullptr; /* bufMemReq.buffer = buffer; */
bufMemReq.buffer = buffer;
memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; /* memReq.pNext = nullptr; */
memReq.pNext = nullptr; /* vk::getBufferMemoryRequirements2(device, &bufMemReq, &memReq); */
vkGetBufferMemoryRequirements2(device, &bufMemReq, &memReq); /* } */
}
void getImageMemoryRequirements(const VkDevice& device, const VkImage& image, VkImageMemoryRequirementsInfo2& imMemReq, VkMemoryRequirements2& memReq) { /* void getImageMemoryRequirements(const vk::Device& device, const vk::Image& image, vk::ImageMemoryRequirementsInfo2& imMemReq, vk::MemoryRequirements2& memReq) { */
imMemReq.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2; /* imMemReq.image = image; */
imMemReq.pNext = nullptr;
imMemReq.image = image;
memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; /* memReq = device.getImageMemoryRequirements2(imMemReq); */
memReq.pNext = nullptr; /* } */
vkGetImageMemoryRequirements2(device, &imMemReq, &memReq);
}
// //
@ -142,7 +143,7 @@ namespace gz::vk {
} }
} // namespace gz::vk } // namespace gz::vlk

View File

@ -5,9 +5,25 @@
#include <optional> #include <optional>
#include <set> #include <set>
#include <unordered_map> #include <unordered_map>
#include <vulkan/vulkan_core.h> #define VULKAN_HPP_NO_CONSTRUCTORS
#define VULKAN_HPP_NO_EXCEPTIONS
#include <vulkan/vulkan.hpp>
namespace gz::vk { #ifdef GZ_UTIL_STRING_CONCEPTS
static_assert(false, "gz-util/util/string_conversion.hpp is included before vulkan_util.hpp!");
#endif
template<typename T>
concept VkToString = requires(const T& t) {
{ vk::to_string(t) };
};
template<VkToString T>
inline std::string toString(const T& t) {
return vk::to_string(t);
}
namespace gz::vlk {
/** /**
* @name Convenience structs * @name Convenience structs
* @details * @details
@ -18,13 +34,14 @@ namespace gz::vk {
* @brief Struct containing all physical device features structs * @brief Struct containing all physical device features structs
* @details * @details
* Make sure to call vkGetPhysicalDeviceFeatures2 with the f member, not this struct itself * Make sure to call vkGetPhysicalDeviceFeatures2 with the f member, not this struct itself
* @todo Redo with vulkan.hpp and vk::StructureChain
*/ */
struct PhysicalDeviceFeatures { struct PhysicalDeviceFeatures {
/** /**
* @brief Initialize the structs with sType and pNext chain f -> f11 -> f12 -> f13 * @brief Initialize the structs with sType and pNext chain f -> f11 -> f12 -> f13
*/ */
PhysicalDeviceFeatures(); PhysicalDeviceFeatures();
VkPhysicalDeviceFeatures2 f{}; VkPhysicalDeviceFeatures2 f {};
VkPhysicalDeviceVulkan11Features f11{}; VkPhysicalDeviceVulkan11Features f11{};
VkPhysicalDeviceVulkan12Features f12{}; VkPhysicalDeviceVulkan12Features f12{};
VkPhysicalDeviceVulkan13Features f13{}; VkPhysicalDeviceVulkan13Features f13{};
@ -38,8 +55,8 @@ namespace gz::vk {
PL_3D, PL_2D PL_3D, PL_2D
}; };
struct Pipeline { struct Pipeline {
VkPipeline pipeline; vk::Pipeline pipeline;
VkPipelineLayout layout; vk::PipelineLayout layout;
void operator=(const Pipeline& other) = delete; void operator=(const Pipeline& other) = delete;
}; };
@ -53,15 +70,15 @@ namespace gz::vk {
/** /**
* @brief Destroy the pipeline+layout and then remove the handles from the underlying map * @brief Destroy the pipeline+layout and then remove the handles from the underlying map
*/ */
void erase(const PipelineT& key, const VkDevice& device, const VkAllocationCallbacks* pAllocator=nullptr); void erase(const PipelineT& key, const vk::Device& device, const vk::AllocationCallbacks* pAllocator=nullptr);
/** /**
* @brief Destroy the pipeline+layout and then remove the handles from the underlying map * @brief Destroy the pipeline+layout and then remove the handles from the underlying map
*/ */
iterator erase(const iterator& it, const VkDevice& device, const VkAllocationCallbacks* pAllocator=nullptr); iterator erase(const iterator& it, const vk::Device& device, const vk::AllocationCallbacks* pAllocator=nullptr);
/** /**
* @brief Destroy all pipelines#layouts and then remove the handles from the underlying map * @brief Destroy all pipelines#layouts and then remove the handles from the underlying map
*/ */
void destroy(const VkDevice& device, const VkAllocationCallbacks* pAllocator=nullptr); void destroy(const vk::Device& device, const vk::AllocationCallbacks* pAllocator=nullptr);
iterator begin() { return pipelines.begin(); } iterator begin() { return pipelines.begin(); }
iterator end() { return pipelines.end(); } iterator end() { return pipelines.end(); }
size_t size() const { return pipelines.size(); } size_t size() const { return pipelines.size(); }
@ -71,9 +88,9 @@ namespace gz::vk {
}; };
struct SwapChainSupport { struct SwapChainSupport {
VkSurfaceCapabilitiesKHR capabilities; vk::SurfaceCapabilities2KHR capabilities;
std::vector<VkSurfaceFormatKHR> formats; std::vector<vk::SurfaceFormat2KHR> formats;
std::vector<VkPresentModeKHR> presentModes; std::vector<vk::PresentModeKHR> presentModes;
}; };
@ -84,12 +101,12 @@ namespace gz::vk {
struct VerticesAndIndices { struct VerticesAndIndices {
std::vector<Vertex3D> vertices; std::vector<Vertex3D> vertices;
std::vector<T> indices; std::vector<T> indices;
constexpr VkIndexType getIndexType() const { constexpr vk::IndexType getIndexType() const {
if (std::same_as<T, uint16_t>) { if (std::same_as<T, uint16_t>) {
return VK_INDEX_TYPE_UINT16; return vk::IndexType::eUint16;
} }
else if (std::same_as<T, uint32_t>) { else if (std::same_as<T, uint32_t>) {
return VK_INDEX_TYPE_UINT32; return vk::IndexType::eUint32;
} }
} }
}; };
@ -124,30 +141,30 @@ namespace gz::vk {
/** /**
* @brief Get a VkDependencyInfo struct for a single image memory barrier * @brief Get a vk::DependencyInfo struct for a single image memory barrier
*/ */
VkDependencyInfo getDepInfo(const VkImageMemoryBarrier2& barrier); vk::DependencyInfo getDepInfo(const vk::ImageMemoryBarrier2& barrier);
/** /**
* @brief Fill bufMeqReq and memReq * @brief Fill bufMeqReq and memReq
* @details * @details
* Fill the structs and call vkGetBufferMemoryRequirements2() * Fill the structs and call vkGetBufferMemoryRequirements2()
*/ */
void getBufferMemoryRequirements(const VkDevice& device, const VkBuffer& buffer, VkBufferMemoryRequirementsInfo2& bufMemReq, VkMemoryRequirements2& memReq); /* void getBufferMemoryRequirements(const vk::Device& device, const vk::Buffer& buffer, vk::BufferMemoryRequirementsInfo2& bufMemReq, vk::MemoryRequirements2& memReq); */
/** /**
* @brief Fill imMemReq and memReq * @brief Fill imMemReq and memReq
* @details * @details
* Fill the structs and call vkGetImageMemoryRequirements2() * Fill the structs and call vkGetImageMemoryRequirements2()
*/ */
void getImageMemoryRequirements(const VkDevice& device, const VkImage& image, VkImageMemoryRequirementsInfo2& imMemReq, VkMemoryRequirements2& memReq); /* void getImageMemoryRequirements(const vk::Device& device, const vk::Image& image, vk::ImageMemoryRequirementsInfo2& imMemReq, vk::MemoryRequirements2& memReq); */
/// @} /// @}
/** /**
* @brief Used for debugging * @brief Used for debugging
* @see VulkanInstance::debugLog * @see VulkanInstance::debugLog
* @details * @details
* Handles like VkDevice are pointers to the actual handle. * Handles like vk::Device are pointers to the actual handle.
* Register the handle to a vulkan object with this struct and call updateHandles(). * Register the handle to a vulkan object with this struct and call updateHandles().
* The handles set will then contain the actual address of the handle, as printed by the validation layers. * The handles set will then contain the actual address of the handle, as printed by the validation layers.
* That means you can check a handle returned by a validation layer * That means you can check a handle returned by a validation layer
@ -169,4 +186,33 @@ namespace gz::vk {
}; };
} // namespace gz::vk
/**
* @brief Check if all required extensions are available
*/
template<std::ranges::forward_range RE, std::ranges::forward_range AE>
bool areExtensionsAvailable(const RE& requiredExtensions, const AE& availableExtensions)
requires std::same_as<std::ranges::range_reference_t<RE>, const char*&> and std::same_as<std::ranges::range_reference_t<AE>, vk::ExtensionProperties&>
{
bool extensionAvailable;
for (const auto& requiredExtension : requiredExtensions) {
extensionAvailable = false;
for (const auto& extension : availableExtensions) {
if (strcmp(requiredExtension, extension.extensionName) == 0) {
extensionAvailable = true;
break;
}
}
if (!extensionAvailable) {
return false;
}
}
return true;
}
/**
* @file
* @brief Various utility structs and functions, as well as toString() overload for vk objects
*/
} // namespace gz::vlk

View File

@ -1,20 +1,21 @@
#include "vertex.hpp" #include "vertex.hpp"
#include <vulkan/vulkan_core.h> #define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include <gz-util/util/string_conversion.hpp> #include <gz-util/util/string_conversion.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
namespace gz::vk { namespace gz::vlk {
const uint32_t BINDING = 0; const uint32_t BINDING = 0;
template<GLM_vec2_or_3 PosVec> template<GLM_vec2_or_3 PosVec>
VkFormat getVkFormat() { vk::Format getVkFormat() {
if (std::same_as<PosVec, glm::vec3>) { if (std::same_as<PosVec, glm::vec3>) {
return VK_FORMAT_R32G32B32_SFLOAT; return vk::Format::eR32G32B32Sfloat;
} }
else if (std::same_as<PosVec, glm::vec2>) { else if (std::same_as<PosVec, glm::vec2>) {
return VK_FORMAT_R32G32_SFLOAT; return vk::Format::eR32G32Sfloat;
} }
} }
@ -29,28 +30,29 @@ VkFormat getVkFormat() {
template<GLM_vec2_or_3 PosVec> template<GLM_vec2_or_3 PosVec>
VkVertexInputBindingDescription Vertex<PosVec>::getBindingDescription() { vk::VertexInputBindingDescription Vertex<PosVec>::getBindingDescription() {
VkVertexInputBindingDescription bindingD{}; vk::VertexInputBindingDescription bindingD {
bindingD.binding = BINDING; .binding = BINDING,
bindingD.stride = sizeof(Vertex<PosVec>); .stride = sizeof(Vertex<PosVec>),
bindingD.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; .inputRate = vk::VertexInputRate::eVertex,
};
return bindingD; return bindingD;
} }
template<GLM_vec2_or_3 PosVec> template<GLM_vec2_or_3 PosVec>
std::array<VkVertexInputAttributeDescription, 3> Vertex<PosVec>::getAttributeDescriptions() { std::array<vk::VertexInputAttributeDescription, 3> Vertex<PosVec>::getAttributeDescriptions() {
std::array<VkVertexInputAttributeDescription, 3> inputAttributeD{}; std::array<vk::VertexInputAttributeDescription, 3> inputAttributeD{};
inputAttributeD[0].binding = BINDING; inputAttributeD[0].binding = BINDING;
inputAttributeD[0].location = 0; inputAttributeD[0].location = 0;
inputAttributeD[0].format = getVkFormat<PosVec>(); inputAttributeD[0].format = getVkFormat<PosVec>();
inputAttributeD[0].offset = offsetof(Vertex, pos); inputAttributeD[0].offset = offsetof(Vertex, pos);
inputAttributeD[1].binding = BINDING; inputAttributeD[1].binding = BINDING;
inputAttributeD[1].location = 1; inputAttributeD[1].location = 1;
inputAttributeD[1].format = VK_FORMAT_R32G32B32_SFLOAT; inputAttributeD[1].format = vk::Format::eR32G32B32Sfloat;
inputAttributeD[1].offset = offsetof(Vertex, color); inputAttributeD[1].offset = offsetof(Vertex, color);
inputAttributeD[2].binding = BINDING; inputAttributeD[2].binding = BINDING;
inputAttributeD[2].location = 2; inputAttributeD[2].location = 2;
inputAttributeD[2].format = VK_FORMAT_R32G32_SFLOAT; inputAttributeD[2].format = vk::Format::eR32G32Sfloat;
inputAttributeD[2].offset = offsetof(Vertex, texCoord); inputAttributeD[2].offset = offsetof(Vertex, texCoord);
return inputAttributeD; return inputAttributeD;
@ -63,11 +65,11 @@ VkFormat getVkFormat() {
template std::string Vertex<glm::vec2>::toString() const; template std::string Vertex<glm::vec2>::toString() const;
template std::string Vertex<glm::vec3>::toString() const; template std::string Vertex<glm::vec3>::toString() const;
template VkVertexInputBindingDescription Vertex<glm::vec2>::getBindingDescription(); template vk::VertexInputBindingDescription Vertex<glm::vec2>::getBindingDescription();
template VkVertexInputBindingDescription Vertex<glm::vec3>::getBindingDescription(); template vk::VertexInputBindingDescription Vertex<glm::vec3>::getBindingDescription();
template std::array<VkVertexInputAttributeDescription, 3> Vertex<glm::vec2>::getAttributeDescriptions(); template std::array<vk::VertexInputAttributeDescription, 3> Vertex<glm::vec2>::getAttributeDescriptions();
template std::array<VkVertexInputAttributeDescription, 3> Vertex<glm::vec3>::getAttributeDescriptions(); template std::array<vk::VertexInputAttributeDescription, 3> Vertex<glm::vec3>::getAttributeDescriptions();
template bool Vertex<glm::vec2>::operator==(const Vertex<glm::vec2>& other) const; template bool Vertex<glm::vec2>::operator==(const Vertex<glm::vec2>& other) const;
template bool Vertex<glm::vec3>::operator==(const Vertex<glm::vec3>& other) const; template bool Vertex<glm::vec3>::operator==(const Vertex<glm::vec3>& other) const;
} // namespace gz::vk } // namespace gz::vlk

View File

@ -6,17 +6,19 @@
#include <array> #include <array>
#include <string> #include <string>
/* #include <vulkan/vulkan_core.h> */
struct VkVertexInputBindingDescription; // defined in vulkan/vulkan.hpp
struct VkVertexInputAttributeDescription; namespace vk {
struct VertexInputBindingDescription;
struct VertexInputAttributeDescription;
}
namespace gz::vk { namespace gz::vlk {
template<typename T> template<typename T>
concept VertexType = requires { concept VertexType = requires {
requires std::same_as<decltype(T::getBindingDescription()), VkVertexInputBindingDescription>; requires std::same_as<decltype(T::getBindingDescription()), vk::VertexInputBindingDescription>;
requires std::ranges::forward_range<decltype(T::getAttributeDescriptions())>; requires std::ranges::forward_range<decltype(T::getAttributeDescriptions())>;
requires std::same_as<std::ranges::range_value_t<decltype(T::getAttributeDescriptions())>, VkVertexInputAttributeDescription>; requires std::same_as<std::ranges::range_value_t<decltype(T::getAttributeDescriptions())>, vk::VertexInputAttributeDescription>;
}; };
template<typename T> template<typename T>
@ -35,12 +37,12 @@ namespace gz::vk {
glm::vec2 texCoord = { 0, 0 }; glm::vec2 texCoord = { 0, 0 };
std::string toString() const; std::string toString() const;
bool operator==(const Vertex& other) const; bool operator==(const Vertex& other) const;
static VkVertexInputBindingDescription getBindingDescription(); static vk::VertexInputBindingDescription getBindingDescription();
static std::array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions(); static std::array<vk::VertexInputAttributeDescription, 3> getAttributeDescriptions();
}; // struct Vertex }; // struct Vertex
using Vertex3D = Vertex<glm::vec3>; using Vertex3D = Vertex<glm::vec3>;
using Vertex2D = Vertex<glm::vec2>; using Vertex2D = Vertex<glm::vec2>;
} // namespace gz::vk } // namespace gz::vlk
@ -48,9 +50,9 @@ namespace gz::vk {
// HASHES // HASHES
// //
namespace std { namespace std {
template<gz::vk::GLM_vec2_or_3 PosVec> template<gz::vlk::GLM_vec2_or_3 PosVec>
struct hash<gz::vk::Vertex<PosVec>> { struct hash<gz::vlk::Vertex<PosVec>> {
size_t operator()(gz::vk::Vertex<PosVec> const& vertex) const { size_t operator()(gz::vlk::Vertex<PosVec> const& vertex) const {
return ((hash<PosVec>()(vertex.pos)) ^ return ((hash<PosVec>()(vertex.pos)) ^
(hash<glm::vec3>()(vertex.color) << 1) >> 1 ) ^ (hash<glm::vec3>()(vertex.color) << 1) >> 1 ) ^
(hash<glm::vec2>()(vertex.texCoord) << 1); (hash<glm::vec2>()(vertex.texCoord) << 1);

View File

@ -1,6 +1,6 @@
#include "vk_convert.hpp" #include "vk_convert.hpp"
bool vkBool2Bool(const VkBool32& b) { bool vkBool2Bool(const vk::Bool32& b) {
if (b == VK_TRUE) { if (b == VK_TRUE) {
return true; return true;
} }
@ -9,7 +9,7 @@ bool vkBool2Bool(const VkBool32& b) {
} }
}; };
VkBool32 bool2VkBool(const bool& b) { vk::Bool32 bool2VkBool(const bool& b) {
if (b) { if (b) {
return VK_TRUE; return VK_TRUE;
} }
@ -18,7 +18,7 @@ VkBool32 bool2VkBool(const bool& b) {
} }
} }
std::string vkBool2String(const VkBool32& b) { std::string vkBool2String(const vk::Bool32& b) {
if (b == VK_TRUE) { if (b == VK_TRUE) {
return "true"; return "true";
} }
@ -27,7 +27,7 @@ std::string vkBool2String(const VkBool32& b) {
} }
}; };
VkBool32 string2VkBool(const std::string& s) { vk::Bool32 string2VkBool(const std::string& s) {
if (s == "true") { if (s == "true") {
return VK_TRUE; return VK_TRUE;
} }

View File

@ -1,9 +1,10 @@
#include <vulkan/vulkan_core.h> #define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include <string> #include <string>
VkBool32 bool2VkBool(const bool& b); vk::Bool32 bool2VkBool(const bool& b);
bool vkBool2Bool(const VkBool32& b); bool vkBool2Bool(const vk::Bool32& b);
VkBool32 string2VkBool(const std::string& s); vk::Bool32 string2VkBool(const std::string& s);
std::string vkBool2String(const VkBool32& b); std::string vkBool2String(const vk::Bool32& b);

View File

@ -5,15 +5,14 @@
#include <glm/vector_relational.hpp> #include <glm/vector_relational.hpp>
#include <gz-util/util/string_conversion.hpp> #include <gz-util/util/string_conversion.hpp>
#include <vulkan/vulkan_core.h>
namespace gz::vk { namespace gz::vlk {
std::string MemoryBlock::toString() const { std::string MemoryBlock::toString() const {
return std::string("<offset: " + gz::toHexString(offset, 0) + ", size: " + gz::toHexString(size, 0) + ", free: " + gz::toString(free) + ">"); return std::string("<offset: " + gz::toHexString(offset, 0) + ", size: " + gz::toHexString(size, 0) + ", free: " + gz::toString(free) + ">");
} }
DeviceMemory::DeviceMemory(VkDeviceSize size_) { DeviceMemory::DeviceMemory(vk::DeviceSize size_) {
size = size_; size = size_;
memory = VK_NULL_HANDLE; memory = VK_NULL_HANDLE;
blocks.emplace_back(MemoryBlock{size, 0, true}); blocks.emplace_back(MemoryBlock{size, 0, true});
@ -23,17 +22,18 @@ namespace gz::vk {
VulkanAllocator::VulkanAllocator(VulkanInstance& instance) VulkanAllocator::VulkanAllocator(VulkanInstance& instance)
: vk(instance) : vk(instance)
{ {
LogCreateInfo logCI{}; LogCreateInfo logCI {
logCI.logfile = "vulkan_allocator.log"; .logfile = "vulkan_allocator.log",
logCI.storeLog = false; .storeLog = false,
logCI.prefix = "Allocator"; .prefix = "Allocator",
logCI.prefixColor = Color::BLACK; .prefixColor = Color::BLACK,
logCI.timeColor = VULKAN_MESSAGE_TIME_COLOR; .timeColor = settings::VULKAN_MESSAGE_TIME_COLOR,
};
aLog = Log(std::move(logCI)); aLog = Log(std::move(logCI));
} }
void VulkanAllocator::allocate(const VkMemoryAllocateInfo& allocI, const VkMemoryRequirements2& memReq, MemoryInfo& memoryInfo) { void VulkanAllocator::allocate(const vk::MemoryAllocateInfo& allocI, const vk::MemoryRequirements2& memReq, MemoryInfo& memoryInfo) {
aLog.log0("allocate: Requesting memory with ( size", toHexString(allocI.allocationSize), aLog.log0("allocate: Requesting memory with ( size", toHexString(allocI.allocationSize),
"), ( memoryTypeIndex", allocI.memoryTypeIndex, "), ( memoryTypeIndex", allocI.memoryTypeIndex,
"), ( alignment", toHexString(memReq.memoryRequirements.alignment), ")"); "), ( alignment", toHexString(memReq.memoryRequirements.alignment), ")");
@ -72,7 +72,7 @@ namespace gz::vk {
memoryInfo.offset = block->offset; memoryInfo.offset = block->offset;
memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex; memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex;
aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks); /* aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks); */
return; return;
} }
} }
@ -80,13 +80,12 @@ namespace gz::vk {
// if nothing is found, allocate new memory // if nothing is found, allocate new memory
memory[allocI.memoryTypeIndex].emplace_back(DeviceMemory(allocI.allocationSize * TODO_ALLOCATION_SIZE_MULTIPLIIER)); memory[allocI.memoryTypeIndex].emplace_back(DeviceMemory(allocI.allocationSize * TODO_ALLOCATION_SIZE_MULTIPLIIER));
VkMemoryAllocateInfo allocI_{}; vk::MemoryAllocateInfo allocI_{};
allocI_.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocI_.memoryTypeIndex = allocI.memoryTypeIndex; allocI_.memoryTypeIndex = allocI.memoryTypeIndex;
allocI_.allocationSize = memory[allocI.memoryTypeIndex].back().size; allocI_.allocationSize = memory[allocI.memoryTypeIndex].back().size;
aLog.log0("allocate: Allocating new memory of size:", gz::toHexString(allocI_.allocationSize, 0), "(memory", memoryInfo.memoryTypeIndex, "-", gz::toString(memory[memoryInfo.memoryTypeIndex].size()) + ")"); aLog.log0("allocate: Allocating new memory of size:", gz::toHexString(allocI_.allocationSize, 0), "(memory", memoryInfo.memoryTypeIndex, "-", gz::toString(memory[memoryInfo.memoryTypeIndex].size()) + ")");
VkResult result = vkAllocateMemory(vk.getDevice(), &allocI_, NO_ALLOC, &memory[allocI.memoryTypeIndex].back().memory); vk::Result result = vk.getDevice().allocateMemory(&allocI_, NO_ALLOC, &memory[allocI.memoryTypeIndex].back().memory);
if (result != VK_SUCCESS) { if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to allocate memory", "VulkanAllocator::allocate"); throw getVkException(result, "Failed to allocate memory", "VulkanAllocator::allocate");
} }
@ -96,11 +95,11 @@ namespace gz::vk {
deviceMemory.blocks.front().size -= allocI.allocationSize; deviceMemory.blocks.front().size -= allocI.allocationSize;
deviceMemory.blocks.emplace_front(MemoryBlock{ allocI.allocationSize, 0, false }); deviceMemory.blocks.emplace_front(MemoryBlock{ allocI.allocationSize, 0, false });
// alignment always satisfied with vkAllocateMemory() and offset 0 // alignment always satisfied with vk::allocateMemory() and offset 0
memoryInfo.memory = deviceMemory.memory; memoryInfo.memory = deviceMemory.memory;
memoryInfo.offset = 0; memoryInfo.offset = 0;
memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex; memoryInfo.memoryTypeIndex = allocI.memoryTypeIndex;
aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(memory[memoryInfo.memoryTypeIndex].size()) + ") Blocks:", deviceMemory.blocks); /* aLog.log0("allocate: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(memory[memoryInfo.memoryTypeIndex].size()) + ") Blocks:", deviceMemory.blocks); */
} }
@ -136,11 +135,11 @@ namespace gz::vk {
memoryInfo.memory = VK_NULL_HANDLE; memoryInfo.memory = VK_NULL_HANDLE;
memoryInfo.offset = 0; memoryInfo.offset = 0;
aLog.log0("free: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks); /* aLog.log0("free: (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") Blocks:", deviceMemory->blocks); */
// if now there is only one free block, everything is free -> deallocate memory // if now there is only one free block, everything is free -> deallocate memory
if (deviceMemory->blocks.size() == 1) { if (deviceMemory->blocks.size() == 1) {
aLog.log0("free: Deallocating (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") of size:", gz::toHexString(deviceMemory->size, 0)); aLog.log0("free: Deallocating (memory", memoryInfo.memoryTypeIndex, "-", gz::toString(deviceMemory - memory[memoryInfo.memoryTypeIndex].begin()) + ") of size:", gz::toHexString(deviceMemory->size, 0));
vkFreeMemory(vk.getDevice(), deviceMemory->memory, NO_ALLOC); vk.getDevice().freeMemory(deviceMemory->memory, NO_ALLOC);
memory[memoryInfo.memoryTypeIndex].erase(deviceMemory); memory[memoryInfo.memoryTypeIndex].erase(deviceMemory);
} }
return; return;
@ -160,11 +159,11 @@ namespace gz::vk {
aLog.warning("cleanup: (memory", memType->first, "-", gz::toString(deviceMemory - memType->second.begin()) + ") Block not freed: ", *block); aLog.warning("cleanup: (memory", memType->first, "-", gz::toString(deviceMemory - memType->second.begin()) + ") Block not freed: ", *block);
} }
aLog.log0("free: Deallocating (memory", memType->first, "-", gz::toString(deviceMemory - memType->second.begin()) + ") of size:", gz::toHexString(deviceMemory->size, 0)); aLog.log0("free: Deallocating (memory", memType->first, "-", gz::toString(deviceMemory - memType->second.begin()) + ") of size:", gz::toHexString(deviceMemory->size, 0));
vkFreeMemory(vk.getDevice(), deviceMemory->memory, NO_ALLOC); vk.getDevice().freeMemory(deviceMemory->memory, NO_ALLOC);
} }
} }
memory.clear(); memory.clear();
} }
} // namespace gz::vk } // namespace gz::vlk

View File

@ -4,27 +4,28 @@
#include <gz-util/log.hpp> #include <gz-util/log.hpp>
#include <initializer_list> #include <initializer_list>
#define VULKAN_HPP_NO_EXCEPTIONS
#define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_core.h>
#include <list> #include <list>
#include <map> #include <map>
/* #include <vulkan/vulkan_core.h> */
namespace gz::vk { namespace gz::vlk {
/** /**
* @brief Contains information about a subsection (block) of a VkDeviceMemory * @brief Contains information about a subsection (block) of a vk::DeviceMemory
*/ */
struct MemoryInfo { struct MemoryInfo {
/** /**
* @brief Handle of the memory * @brief Handle of the memory
*/ */
VkDeviceMemory memory = VK_NULL_HANDLE; vk::DeviceMemory memory = VK_NULL_HANDLE;
/** /**
* @brief Offset into memory * @brief Offset into memory
*/ */
VkDeviceSize offset = 0; vk::DeviceSize offset = 0;
/** /**
* @brief The memoryTypeIndex memory was allocated from. Needed for VulkanAllocator::free() * @brief The memoryTypeIndex memory was allocated from. Needed for VulkanAllocator::free()
*/ */
@ -42,20 +43,20 @@ namespace gz::vk {
}; };
/** /**
* @brief Manage a single VkDeviceMemory chunk * @brief Manage a single vk::DeviceMemory chunk
*/ */
struct DeviceMemory { struct DeviceMemory {
DeviceMemory() = delete; DeviceMemory() = delete;
DeviceMemory(VkDeviceSize size_); DeviceMemory(vk::DeviceSize size_);
VkDeviceSize size; vk::DeviceSize size;
VkDeviceMemory memory; vk::DeviceMemory memory;
std::list<MemoryBlock> blocks; std::list<MemoryBlock> blocks;
}; };
// if no memory is available, allocate a chunk of multiplier * requested size // if no memory is available, allocate a chunk of multiplier * requested size
constexpr VkDeviceSize TODO_ALLOCATION_SIZE_MULTIPLIIER = 10; constexpr vk::DeviceSize TODO_ALLOCATION_SIZE_MULTIPLIIER = 10;
// defined in vulkan_instance.hpp // defined in vulkan_instance.hpp
@ -64,7 +65,7 @@ namespace gz::vk {
/** /**
* @brief Allocator for device local memory * @brief Allocator for device local memory
* @details * @details
* Allocates larger chunks of VkDeviceMemory from which blocks can be @ref allocate() "allocated". * Allocates larger chunks of vk::DeviceMemory from which blocks can be @ref allocate() "allocated".
* *
* This class is for device local memory only, not for host memory. * This class is for device local memory only, not for host memory.
* You can not use it for vulkan memory allocation callbacks (pAllocator). * You can not use it for vulkan memory allocation callbacks (pAllocator).
@ -73,34 +74,34 @@ namespace gz::vk {
* The usage is explained with the example of creating and destroying a single buffer. * The usage is explained with the example of creating and destroying a single buffer.
* @code * @code
* // Create buffer handle * // Create buffer handle
* VkBuffer buffer; * vk::Buffer buffer;
* // Create empty memory info struct * // Create empty memory info struct
* MemoryInfo bufferMI; * MemoryInfo bufferMI;
* *
* VkBufferCreateInfo bufferCI{} * vk::BufferCreateInfo bufferCI{}
* ... * ...
* vkCreateBuffer(...); * vk::createBuffer(...);
* *
* // get memory requirements * // get memory requirements
* VkMemoryRequirements2 memReq; * vk::MemoryRequirements2 memReq;
* VkBufferMemoryRequirementsInfo2 bufMemReq; * vk::BufferMemoryRequirementsInfo2 bufMemReq;
* // from vulkan_util.hpp, same exists for imageMemoryRequirements * // from vulkan_util.hpp, same exists for imageMemoryRequirements
* getBufferMemoryRequirements(device, buffer, bufMemReq, memReq); * getBufferMemoryRequirements(device, buffer, bufMemReq, memReq);
* *
* // set allocation info * // set allocation info
* VkMemoryAllocateInfo memAI{}; * vk::MemoryAllocateInfo memAI {
* ... * ...
* memAI.memoryTypeIndex = VulkanInstance::findMemoryType(memReq.memoryRequirements.memoryTypeBits, wantedProperties); * .memoryTypeIndex = VulkanInstance::findMemoryType(memReq.memoryRequirements.memoryTypeBits, wantedProperties),
* *
* // allocate memory for the buffer * // allocate memory for the buffer
* VulkanAllocator::allocate(memAI, memReq, bufferMI); * VulkanAllocator::allocate(memAI, memReq, bufferMI);
* *
* // bind the buffer to the memory * // bind the buffer to the memory
* vkBindBufferMemory(device, buffer, bufferMI.memory, bufferMI.offset); * device.bindBufferMemory(buffer, bufferMI.memory, bufferMI.offset);
* *
* ... * ...
* *
* vkDestroyBuffer(device, buffer); * device.destroyBuffer(buffer);
* VulkanAllocator::free(bufferMemoryInfo); * VulkanAllocator::free(bufferMemoryInfo);
* @endcode * @endcode
* *
@ -110,23 +111,23 @@ namespace gz::vk {
public: public:
VulkanAllocator(VulkanInstance& instance); VulkanAllocator(VulkanInstance& instance);
/** /**
* @brief Get a block from a VkDeviceMemory * @brief Get a block from a vk::DeviceMemory
* @details * @details
* Get a block of allocI.allocationSize of a VkDeviceMemory that was allocated with allocI.memoryTypeIndex. * Get a block of allocI.allocationSize of a vk::DeviceMemory that was allocated with allocI.memoryTypeIndex.
* *
* When this function returns, memoryInfo will contain the information about the available block. * When this function returns, memoryInfo will contain the information about the available block.
* You can then bind something of size allocI.allocationSize to memoryInfo.memory at offset memoryInfo.offset. * You can then bind something of size allocI.allocationSize to memoryInfo.memory at offset memoryInfo.offset.
* @throws VkException when a call to vkAllocateMemory is needed and fails * @throws vk::Exception when a call to vkAllocateMemory is needed and fails
* @todo Determine the size of new allocations * @todo Determine the size of new allocations
* @todo alignment, maybe use VkMemoryRequirements instead of VkMemoryAllocateInfo? * @todo alignment, maybe use vk::MemoryRequirements instead of vk::MemoryAllocateInfo?
* @todo maybe increase the block size of the allocated block so that the following blocks is already 16-aligned? * @todo maybe increase the block size of the allocated block so that the following blocks is already 16-aligned?
*/ */
void allocate(const VkMemoryAllocateInfo& allocI, const VkMemoryRequirements2& memReq, MemoryInfo& memoryInfo); void allocate(const vk::MemoryAllocateInfo& allocI, const vk::MemoryRequirements2& memReq, MemoryInfo& memoryInfo);
/** /**
* @brief Free a block allocated with allocate() * @brief Free a block allocated with allocate()
* *
* When this function returns, memoryInfo will be reset to default values * When this function returns, memoryInfo will be reset to default values
* @throws VkUserError if memoryInfo was not allocated from this allocator * @throws vk::UserError if memoryInfo was not allocated from this allocator
*/ */
void free(MemoryInfo& memoryInfo); void free(MemoryInfo& memoryInfo);
@ -147,4 +148,4 @@ namespace gz::vk {
VulkanInstance& vk; VulkanInstance& vk;
}; // class VulkanAllocator }; // class VulkanAllocator
} // namespace gz::vk } // namespace gz::vlk

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +1,45 @@
#pragma once #pragma once
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp> /* #include <glm/glm.hpp> */
#define GLFW_INCLUDE_VULKAN #define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#define VULKAN_HPP_NO_EXCEPTIONS
#define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include "vk_convert.hpp" #include "vk_convert.hpp"
#include "vertex.hpp" #include "vertex.hpp"
#include "shape.hpp"
#include "vulkan_util.hpp" #include "vulkan_util.hpp"
#include "vulkan_allocator.hpp" #include "vulkan_allocator.hpp"
#include "vulkan_settings.hpp"
#include <gz-util/log.hpp> #include <gz-util/log.hpp>
#include <gz-util/settings_manager.hpp> #include <gz-util/settings_manager.hpp>
#include <gz-util/util/string.hpp> #include <gz-util/util/string.hpp>
#include <vulkan/vulkan_core.h>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
namespace gz::vk { namespace gz::vlk {
constexpr bool throwExceptionOnValidationError = true; constexpr vk::MemoryMapFlags NO_MEM_FLAGS;
constexpr gz::Color VULKAN_MESSAGE_PREFIX_COLOR = gz::Color::BO_BLUE; constexpr vk::AccessFlags NO_ACC_FLAGS;
constexpr gz::Color VULKAN_MESSAGE_TIME_COLOR = gz::Color::BLUE; constexpr vk::AccessFlags2 NO_ACC_2_FLAGS;
const std::string CONFIG_FILE = "vulkan.conf"; constexpr vk::CommandBufferResetFlags NO_CMD_RESET_FLAGS;
#define SettingsTypes uint32_t, bool, float
/* const std::string MODEL_PATH = "models/gazebo-3d-model/gazebo.obj"; */
/* const std::string TEXTURE_PATH = "models/gazebo-3d-model/gazebo_diffuse.png"; */
const std::string MODEL_PATH = "models/armoire-3d-model/Armoire.obj";
const std::string TEXTURE_PATH = "models/armoire-3d-model/Armoire_diffuse.png";
const gz::util::unordered_string_map<std::string> INITIAL_SETTINGS = {
{ "framerate", "60" },
{ "anisotropy_enable", "false" },
{ "max_anisotropy", "1" },
{ "max_frames_in_flight", "3" },
/* { "", "" } */
};
constexpr VkClearColorValue missingTextureColor = { { 0.4f, 0.0f, 0.4f, 1.0f } };
const int BINDING = 0;
const uint32_t NO_FLAGS = 0;
const uint32_t NO_OFFSET = 0; const uint32_t NO_OFFSET = 0;
constexpr VkAllocationCallbacks* NO_ALLOC = nullptr; constexpr vk::AllocationCallbacks* NO_ALLOC = nullptr;
const size_t VERTEX_BUFFER_SIZE = 512; /* const vk::ImageSubresourceRange DEFAULT_SUBRESOURCE_RANGE { */
const size_t INDEX_BUFFER_SIZE = 512; /* .aspectMask = vk::ImageAspectFlagBits::eColor, */
/* .baseMipLevel = 0, */
/* .levelCount = 1, */
/* .baseArrayLayer = 0, */
/* .layerCount = 1, */
/* }; */
enum InstanceCommandPool { enum InstanceCommandPool {
POOL_GRAPHICS, POOL_TRANSFER POOL_GRAPHICS, POOL_TRANSFER
}; };
@ -67,7 +55,7 @@ namespace gz::vk {
* These functions will probably called from your `main` function and loop. * These functions will probably called from your `main` function and loop.
*/ */
/// @{ /// @{
VulkanInstance(gz::SettingsManagerCreateInfo<SettingsTypes>smCI) : settings(smCI), allocator(*this) {}; VulkanInstance(gz::SettingsManagerCreateInfo<VULKAN_SETTINGS_MAN_TYPES>smCI) : settings(smCI), allocator(*this) {};
/** /**
* @brief Initializes the vulkan instance * @brief Initializes the vulkan instance
* @details * @details
@ -158,12 +146,13 @@ namespace gz::vk {
*/ */
public: public:
/// @{ /// @{
const VkDevice& getDevice() const { return device; } const vk::Device& getDevice() const { return device; }
const VkExtent2D& getScExtent() const { return scExtent; } const vk::Extent2D& getScExtent() const { return scExtent; }
const std::vector<VkImage>& getScImages() const { return scImages; } const std::vector<vk::Image>& getScImages() const { return scImages; }
const VkFormat& getScImageFormat() const { return scImageFormat; } const vk::Format& getScImageFormat() const { return scImageFormat; }
const vk::Format& getDepthFormat() const { return depthFormat; }
SettingsManager<SettingsTypes>& getSettings() { return settings; } SettingsManager<VULKAN_SETTINGS_MAN_TYPES>& getSettings() { return settings; }
/** /**
* @brief Get the maximum number of frames in flight * @brief Get the maximum number of frames in flight
@ -176,28 +165,30 @@ namespace gz::vk {
*/ */
uint32_t getCurrentFrame() const { return currentFrame; } uint32_t getCurrentFrame() const { return currentFrame; }
void submitThisFrame(VkCommandBuffer& cmdBuffer); void submitThisFrame(vk::CommandBuffer& cmdBuffer);
/** /**
* @brief Copy from srcBuffer to dstBuffer * @brief Copy from srcBuffer to dstBuffer
* @details * @details
* Uses @ref beginSingleTimeCommands() "a single time command buffer" from commandPoolTransfer. * Uses @ref beginSingleTimeCommands() "a single time command buffer" from commandPoolTransfer.
*/ */
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); void copyBuffer(vk::Buffer srcBuffer, vk::Buffer dstBuffer, vk::DeviceSize size);
/** /**
* @brief Begin a command buffer that is going to be used once * @brief Begin a command buffer that is going to be used once
* @param commandPool: The command pool from which the buffer should be allocated * @param commandPool: The command pool from which the buffer should be allocated
*/ */
VkCommandBuffer beginSingleTimeCommands(InstanceCommandPool commandPool); vk::CommandBuffer beginSingleTimeCommands(InstanceCommandPool commandPool);
/** /**
* @brief Submit cmdBuffer on the queue and free it afterwards * @brief Submit cmdBuffer on the queue and free it afterwards
* @param cmdBuffer: Command buffer returned by beginSingleTimeCommands() * @param cmdBuffer: Command buffer returned by beginSingleTimeCommands()
* @param commandPool: The same pool as passed to beginSingleTimeCommands() * @param commandPool: The same pool as passed to beginSingleTimeCommands()
* @details
* After command buffer is submitted on the specified queue, the function waits for the queue to idle
*/ */
void endSingleTimeCommands(VkCommandBuffer cmdBuffer, InstanceCommandPool commandPool); void endSingleTimeCommands(vk::CommandBuffer cmdBuffer, InstanceCommandPool commandPool);
void loadModel(VerticesAndIndices<uint32_t>& model); void loadModel(const std::string& path, VerticesAndIndices<uint32_t>& model);
/// @} /// @}
/** /**
@ -212,16 +203,16 @@ namespace gz::vk {
/** /**
* @brief Create MAX_FRAMES_IN_FLIGHT command buffers from the commandPoolGraphics * @brief Create MAX_FRAMES_IN_FLIGHT command buffers from the commandPoolGraphics
*/ */
void createCommandBuffers(std::vector<VkCommandBuffer>& commandBuffers); void createCommandBuffers(std::vector<vk::CommandBuffer>& commandBuffers);
/** /**
* @brief Destroy all command buffers (must be from commandPoolGraphics) * @brief Destroy all command buffers (must be from commandPoolGraphics)
*/ */
void destroyCommandBuffers(std::vector<VkCommandBuffer>& commandBuffers); void destroyCommandBuffers(std::vector<vk::CommandBuffer>& commandBuffers);
/** /**
* @brief Create a descriptor layout with bindings * @brief Create a descriptor layout with bindings
*/ */
void createDescriptorSetLayout(std::vector<VkDescriptorSetLayoutBinding> bindings, VkDescriptorSetLayout& layout); void createDescriptorSetLayout(std::vector<vk::DescriptorSetLayoutBinding> bindings, vk::DescriptorSetLayout& layout);
/** /**
* @brief Create a new graphics pipeline * @brief Create a new graphics pipeline
@ -236,17 +227,19 @@ namespace gz::vk {
* @details * @details
* Create a pipeline with: * Create a pipeline with:
* - 2 shader stages: vertex and fragment shader * - 2 shader stages: vertex and fragment shader
* - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, vertices are triangles * - vk::PrimitiveTopology::eTriangleList, vertices are triangles
* - viewport viewing the whole image as described by scExtent * - viewport viewing the whole image as described by scExtent
* - scissor with offset (0, 0) * - scissor with offset (0, 0)
* - rasterizer: * - rasterizer:
* - triangles are filled with the colors from the vertex (VK_POLYGON_FILL) * - triangles are filled with the colors from the vertex (VK_POLYGON_FILL)
* - counter clockwise front face (VK_FRONT_FACE_COUNTER_CLOCKWISE) * - counter clockwise front face (vk::FrontFace::eCounterClockwise)
*
* @todo Move shader module creation and maybe pipelineshaderstagecreateinfo outside
*/ */
template<VertexType T> template<VertexType T>
void createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector<VkDescriptorSetLayout>& descriptorSetLayouts, bool useDepthStencil, VkRenderPass& renderPass, Pipeline& pipeline); 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);
VkShaderModule createShaderModule(const std::vector<char>& code); vk::ShaderModule createShaderModule(const std::vector<char>& code);
/** /**
* @brief Allocate memory, create a buffer and bind buffer to memory * @brief Allocate memory, create a buffer and bind buffer to memory
@ -254,15 +247,16 @@ namespace gz::vk {
* @param buffer The (null) handle to the buffer * @param buffer The (null) handle to the buffer
* @param bufferMemory Reference to an (uninitialized) MemoryInfo struct. It will be valid when the function returns * @param bufferMemory Reference to an (uninitialized) MemoryInfo struct. It will be valid when the function returns
* @param properties Properties that the buffers memory needs to satisfy * @param properties Properties that the buffers memory needs to satisfy
* @param qFamiliesWithAccess [Optional] vector of queue families that have access to the buffer. Only needed with SHARING_MODE_CONCURRENT
* @details * @details
* The memory the buffer will be bound to is HOST_VISIBLE and HOST_COHERENT * The memory the buffer will be bound to is HOST_VISIBLE and HOST_COHERENT
* *
*/ */
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, MemoryInfo& bufferMemory, VkSharingMode sharingMode=VK_SHARING_MODE_EXCLUSIVE, std::vector<uint32_t>* qFamiliesWithAccess=nullptr); void createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties, vk::Buffer& buffer, MemoryInfo& bufferMemory, vk::SharingMode sharingMode=vk::SharingMode::eExclusive, std::vector<uint32_t>* qFamiliesWithAccess=nullptr);
/** /**
* @brief Destroy buffer and free memory * @brief Destroy buffer and free memory
*/ */
void destroyBuffer(VkBuffer& buffer, MemoryInfo& bufferMemory); void destroyBuffer(vk::Buffer& buffer, MemoryInfo& bufferMemory);
/** /**
* @brief Create a vertex buffer * @brief Create a vertex buffer
@ -273,7 +267,7 @@ namespace gz::vk {
* The function is instantiated for Vertex2D and Vertex3D * The function is instantiated for Vertex2D and Vertex3D
*/ */
template<VertexType VertexT> template<VertexType VertexT>
void createVertexBuffer(size_t vertexCount, VkBuffer& vertexBuffer, MemoryInfo& vertexBufferMemory, VkDeviceSize& vertexBufferSize); void createVertexBuffer(size_t vertexCount, vk::Buffer& vertexBuffer, MemoryInfo& vertexBufferMemory, vk::DeviceSize& vertexBufferSize);
/** /**
* @brief Create an index buffer * @brief Create an index buffer
@ -284,30 +278,30 @@ namespace gz::vk {
* The function is instantiated for uint16_t and uint32_t * The function is instantiated for uint16_t and uint32_t
*/ */
template<SupportedIndexType T> template<SupportedIndexType T>
void createIndexBuffer(size_t indexCount, VkBuffer& indexBuffer, MemoryInfo& indexBufferMemory, VkDeviceSize& indexBufferSize); void createIndexBuffer(size_t indexCount, vk::Buffer& indexBuffer, MemoryInfo& indexBufferMemory, vk::DeviceSize& indexBufferSize);
/** /**
* @brief Create MAX_FRAMES_IN_FLIGHT uniform buffers * @brief Create MAX_FRAMES_IN_FLIGHT uniform buffers
*/ */
template<typename T> template<typename T>
void createUniformBuffers(std::vector<VkBuffer>& 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 the swap chain has images, with the extent of the swap chain
*/ */
void createFramebuffers(std::vector<VkFramebuffer>& framebuffers, std::vector<VkImageView>& imageViews, VkRenderPass& renderPass); void createFramebuffers(std::vector<vk::Framebuffer>& framebuffers, std::vector<vk::ImageView>& imageViews, vk::RenderPass& renderPass, vk::ImageView depthImageView=VK_NULL_HANDLE);
/** /**
* @brief Destroy the framebuffers * @brief Destroy the framebuffers
*/ */
void destroyFramebuffers(std::vector<VkFramebuffer>& framebuffers); void destroyFramebuffers(std::vector<vk::Framebuffer>& framebuffers);
/** /**
* @brief Create a texture sampler * @brief Create a texture sampler
* @todo add options and documentation * @todo add options and documentation
*/ */
void createTextureSampler(VkSampler& sampler); void createTextureSampler(vk::Sampler& sampler);
void destroyTextureSampler(VkSampler& sampler); void destroyTextureSampler(vk::Sampler& sampler);
/** /**
* @name Public Interface: Image utility * @name Public Interface: Image utility
@ -319,15 +313,15 @@ namespace gz::vk {
/** /**
* @brief Create a 2D image, allocate the imageMemory and bind the image to it * @brief Create a 2D image, allocate the imageMemory and bind the image to it
*/ */
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkImage& image, MemoryInfo& imageMI); void createImage(uint32_t width, uint32_t height, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags memoryProperties, vk::Image& image, MemoryInfo& imageMI);
void destroyImage(VkImage& image, MemoryInfo& imageMemory); void destroyImage(vk::Image& image, MemoryInfo& imageMemory);
/** /**
* @brief Create a 2D imageView with format for image. * @brief Create a 2D imageView with format for image.
*/ */
void createImageView(VkFormat format, VkImage& image, VkImageView& imageView, VkImageAspectFlags aspectFlags); void createImageView(vk::Format format, vk::Image& image, vk::ImageView& imageView, vk::ImageAspectFlags aspectFlags);
void destroyImageView(VkImageView& imageView); void destroyImageView(vk::ImageView& imageView);
void copyBufferToImage(VkBuffer buffer, VkImage image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height); void copyBufferToImage(vk::Buffer buffer, vk::Image image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height);
/** /**
* @todo make a version using vkCmdResolveImage for multisampled images * @todo make a version using vkCmdResolveImage for multisampled images
* @brief Copy srcImage to dstImage * @brief Copy srcImage to dstImage
@ -342,7 +336,7 @@ namespace gz::vk {
* @param srcImage Image with layout TRANSFER_SRC_OPTIMAL * @param srcImage Image with layout TRANSFER_SRC_OPTIMAL
* @param dstImage Image with layout TRANSFER_DST_OPTIMAL * @param dstImage Image with layout TRANSFER_DST_OPTIMAL
*/ */
void copyImageToImage(VkCommandBuffer& cmdBuffer, VkImage srcImage, VkImage dstImage, VkExtent2D extent); //, VkCommandPool& commandPool=commandPoolTransfer); void copyImageToImage(vk::CommandBuffer& cmdBuffer, vk::Image srcImage, vk::Image dstImage, vk::Extent2D extent); //, vk::CommandPool& commandPool=commandPoolTransfer);
/** /**
* @brief Transition the layout of image from oldLayout to newLayout * @brief Transition the layout of image from oldLayout to newLayout
* @details * @details
@ -356,12 +350,12 @@ namespace gz::vk {
* If you do not provide a command buffer, a command buffer from the indicated queue will be created and submitted. * If you do not provide a command buffer, a command buffer from the indicated queue will be created and submitted.
* If you do provide a command buffer, the command is recorded but NOT submitted. * If you do provide a command buffer, the command is recorded but NOT submitted.
* *
* The transition is done by submitting a VkImageMemoryBarrier2 * The transition is done by submitting a vk::ImageMemoryBarrier2
* *
* @param cmdBuffer [Optional] The command buffer where the command will be recorded to * @param cmdBuffer [Optional] The command buffer where the command will be recorded to
* @throws VkUserError if the transition is not supported. * @throws vk::UserError if the transition is not supported.
*/ */
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandBuffer* cmdBuffer=nullptr); void transitionImageLayout(vk::Image image, vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout, vk::CommandBuffer* cmdBuffer=nullptr);
/// @} /// @}
@ -393,7 +387,7 @@ namespace gz::vk {
* @name Settings * @name Settings
*/ */
/// @{ /// @{
gz::SettingsManager<SettingsTypes> settings; gz::SettingsManager<VULKAN_SETTINGS_MAN_TYPES> settings;
/** /**
* @brief Set valid values for the SettingsManager according to phDevFeatures and phDevProperties * @brief Set valid values for the SettingsManager according to phDevFeatures and phDevProperties
* @details * @details
@ -457,37 +451,48 @@ namespace gz::vk {
* @name Instance * @name Instance
*/ */
/// @{ /// @{
VkInstance instance; vk::Instance instance;
/** /**
* @brief Create the vulkan instance * @brief Create the vulkan instance
* @details * @details
* -# check if validationLayers are available (if enabled) * -# check if validationLayers are available (if enabled)
* -# create instance with info * -# create instance with info
* -# check if all extensions required by glfw are available * -# check if all extensions required by glfw are available
* @throws VkException if:
* - validation layers are enabled but not supported
* - instance creation fails
* - not all required instance extensions are available
*/ */
void createInstance(); void createInstance();
/**
* @brief Get all the required instance extensions
* @details
* The required extensions are:
* - all extensions required by glfw (glfwGetRequiredInstanceExtensions())
* - if validation layers are enabled: "VK_EXT_debug_utils"
*/
std::vector<const char*> getRequiredInstanceExtensions() const;
/**
* @brief Check if @ref settings::validationLayers "all requrested validation layers" are supported
*/
bool validationLayersSupported();
/// @} /// @}
/** /**
* @name Physical device * @name Physical device (selection process)
* @brief Member variables and functions that are used to select a physical device
*/ */
/// @{ /// @{
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
/// all the properties of the selected physcial device
VkPhysicalDeviceProperties phDevProperties;
/// all the features that the selected physical device supports
PhysicalDeviceFeatures phDevFeatures;
/**
* @brief Get the required physical device features
* @details
* The required features are:
* - synchronization2
*/
PhysicalDeviceFeatures getRequiredFeatures() const;
/** /**
* @brief Assign the physicalDevice handle to the @ref rateDevice "best rated" GPU * @brief Assign the physicalDevice handle to the @ref rateDevice "best rated" GPU
* @details * @details
* After this method, physicalDevice, phDevProperties and phDevFeatures will be initialized * After this method, the following members will be initalized:
* - physicalDevice
* - phDevProperties
* - phDevFeatures
* - phDevMemProperties
* - qFamilyIndices
* - depthFormat
*/ */
void selectPhysicalDevice(); void selectPhysicalDevice();
/** /**
@ -499,20 +504,44 @@ namespace gz::vk {
* - support all necessary extensions * - support all necessary extensions
* - have swap chain support * - have swap chain support
*/ */
unsigned int rateDevice(VkPhysicalDevice device); unsigned int rateDevice(vk::PhysicalDevice device);
/**
* @brief Get the required physical device features
* @details
* The required features are:
* - synchronization2
*/
PhysicalDeviceFeatures getRequiredDeviceFeatures() const;
/**
* @name Physical device (selected)
* @brief Member variables and functions that are usable/initalized after selectPhysicalDevice
*/
/// @{
vk::PhysicalDevice physicalDevice = VK_NULL_HANDLE;
/// all the properties of the selected physcial device
vk::PhysicalDeviceProperties2 phDevProperties;
/// memory properties of the selected physical device
vk::PhysicalDeviceMemoryProperties2 phDevMemProperties;
/// all the features that the selected physical device supports
PhysicalDeviceFeatures phDevFeatures;
/// preferred depth format
vk::Format depthFormat;
/** /**
* @brief Find the best of the supported formats * @brief Find the best of the supported formats
* @param candidates Candidate format, from best to worst * @param candidates Candidate format, from best to worst
* @returns The first format from candidates that is supported * @returns The first format from candidates that is supported
* @throws VkException if no suitable format is found
*/ */
VkFormat findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features); vk::Format findSupportedFormat(const std::vector<vk::Format>& candidates, vk::ImageTiling tiling, vk::FormatFeatureFlags features);
/// @} /// @}
/** /**
* @name Memory management * @name Memory management
*/ */
/// @{ /// @{
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); uint32_t findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties);
VulkanAllocator allocator; VulkanAllocator allocator;
/// @} /// @}
@ -520,19 +549,19 @@ namespace gz::vk {
* @name Queue * @name Queue
*/ */
/// @{ /// @{
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); QueueFamilyIndices findQueueFamilies(vk::PhysicalDevice device);
QueueFamilyIndices qFamilyIndices; QueueFamilyIndices qFamilyIndices;
VkQueue graphicsQ; vk::Queue graphicsQ;
VkQueue presentQ; vk::Queue presentQ;
// if possible, use dedicated transferQ. if not available, transferQ = graphicsQ // if possible, use dedicated transferQ. if not available, transferQ = graphicsQ
VkQueue transferQ; vk::Queue transferQ;
/// @} /// @}
/** /**
* @name Logical device * @name Logical device
*/ */
/// @{ /// @{
VkDevice device; vk::Device device;
/** /**
* @details * @details
* request anisotropic sampling feature * request anisotropic sampling feature
@ -544,7 +573,7 @@ namespace gz::vk {
* @name Surface * @name Surface
*/ */
/// @{ /// @{
VkSurfaceKHR surface; vk::SurfaceKHR surface;
void createSurface(); void createSurface();
/// @} /// @}
@ -552,22 +581,23 @@ namespace gz::vk {
* @name Swap chain * @name Swap chain
*/ */
/// @{ /// @{
VkSwapchainKHR swapChain; vk::SwapchainKHR swapChain;
std::vector<VkImage> scImages; std::vector<vk::Image> scImages;
std::vector<VkImageView> scImageViews; std::vector<vk::ImageView> scImageViews;
VkFormat scImageFormat; vk::Format scImageFormat;
VkExtent2D scExtent; vk::Extent2D scExtent;
SwapChainSupport querySwapChainSupport(VkPhysicalDevice device); SwapChainSupport querySwapChainSupport(vk::PhysicalDevice device);
/** /**
* @todo Rate formats if preferred is not available * @todo Rate formats if preferred is not available
* @todo Move back to SurfaceFormatKHR? 2 is an (for now) unnecessary extension
*/ */
VkSurfaceFormatKHR selectSwapChainSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats); vk::SurfaceFormat2KHR selectSwapChainSurfaceFormat(const std::vector<vk::SurfaceFormat2KHR>& availableFormats);
/** /**
* @todo Check settings for preferred mode * @todo Check settings for preferred mode
*/ */
VkPresentModeKHR selectSwapChainPresentMode(const std::vector<VkPresentModeKHR>& availableModes); vk::PresentModeKHR selectSwapChainPresentMode(const std::vector<vk::PresentModeKHR>& availableModes);
VkExtent2D selectSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); vk::Extent2D selectSwapExtent(const vk::SurfaceCapabilities2KHR& capabilities);
void createSwapChain(); void createSwapChain();
void createSwapChainImageViews(); void createSwapChainImageViews();
void cleanupSwapChain(); void cleanupSwapChain();
@ -589,31 +619,31 @@ namespace gz::vk {
* @name Command pools * @name Command pools
*/ */
/// @{ /// @{
VkCommandPool commandPoolGraphics; vk::CommandPool commandPoolGraphics;
VkCommandPool commandPoolTransfer; vk::CommandPool commandPoolTransfer;
void createCommandPools(); void createCommandPools();
/// @} /// @}
/** /**
* @name Command buffers * @name Command buffers
*/ */
/// @{ /// @{
std::vector<VkCommandBuffer> commandBuffersBegin; std::vector<vk::CommandBuffer> commandBuffersBegin;
std::vector<VkCommandBuffer> commandBuffersEnd; std::vector<vk::CommandBuffer> commandBuffersEnd;
/** /**
* @brief All command buffers to submit on graphics queue for the current frame * @brief All command buffers to submit on graphics queue for the current frame
* @details * @details
* Use submitThisFrame() to submit a command buffer * Use submitThisFrame() to submit a command buffer
*/ */
std::vector<VkCommandBuffer> commandBuffersToSubmitThisFrame; std::vector<vk::CommandBuffer> commandBuffersToSubmitThisFrame;
/// @} /// @}
/** /**
* @name Synchronization * @name Synchronization
*/ */
/// @{ /// @{
std::vector<VkSemaphore> imageAvailableSemaphores; std::vector<vk::Semaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores; std::vector<vk::Semaphore> renderFinishedSemaphores;
std::vector<VkFence> inFlightFences; std::vector<vk::Fence> inFlightFences;
void createSyncObjects(); void createSyncObjects();
/// @} /// @}
@ -634,7 +664,7 @@ namespace gz::vk {
*/ */
/// @{ /// @{
template<typename T, typename... Args> template<typename T, typename... Args>
VkResult runVkResultFunction(const char* name, Args&&... args); vk::Result runVkResultFunction(const char* name, Args&&... args);
template<typename T, typename... Args> template<typename T, typename... Args>
void runVkVoidFunction(const char* name, Args&&... args); void runVkVoidFunction(const char* name, Args&&... args);
@ -676,14 +706,14 @@ namespace gz::vk {
// UNIFORM BUFFERS // UNIFORM BUFFERS
// //
template<typename T> template<typename T>
void VulkanInstance::createUniformBuffers(std::vector<VkBuffer>& uniformBuffers, std::vector<MemoryInfo>& uniformBuffersMemory) { void VulkanInstance::createUniformBuffers(std::vector<vk::Buffer>& uniformBuffers, std::vector<MemoryInfo>& uniformBuffersMemory) {
VkDeviceSize bufferSize = sizeof(T); vk::DeviceSize bufferSize = sizeof(T);
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT); uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT); uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]); createBuffer(bufferSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, uniformBuffers[i], uniformBuffersMemory[i]);
} }
} }
@ -691,14 +721,14 @@ namespace gz::vk {
// UTILITY // UTILITY
// //
template<typename T, typename... Args> template<typename T, typename... Args>
VkResult 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));
if (f == nullptr) { if (f == nullptr) {
vLog.error("getVkFunction: Could not get function:", name); vLog.error("getVkFunction: Could not get function:", name);
throw std::runtime_error("getVkFunction: Could not get function."); throw std::runtime_error("getVkFunction: Could not get function.");
} }
else { else {
return f(std::forward<Args>(args)...); return vk::Result(f(std::forward<Args>(args)...));
} }
}; };

72
src/vulkan_settings.hpp Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <gz-util/settings_manager.hpp>
#include <gz-util/log.hpp>
#define VULKAN_HPP_NO_EXCEPTIONS
#define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
namespace gz::vlk::settings {
constexpr bool throwExceptionOnValidationError = true;
constexpr gz::Color VULKAN_MESSAGE_PREFIX_COLOR = gz::Color::BO_BLUE;
constexpr gz::Color VULKAN_MESSAGE_TIME_COLOR = gz::Color::BLUE;
const std::string CONFIG_FILE = "vulkan.conf";
/* const std::string MODEL_PATH = "models/gazebo-3d-model/gazebo.obj"; */
/* const std::string TEXTURE_PATH = "models/gazebo-3d-model/gazebo_diffuse.png"; */
const std::string MODEL_PATH = "models/armoire-3d-model/Armoire.obj";
const std::string TEXTURE_PATH = "models/armoire-3d-model/Armoire_diffuse.png";
#define VULKAN_SETTINGS_MAN_TYPES uint32_t, bool, float
const gz::util::unordered_string_map<std::string> INITIAL_SETTINGS = {
{ "framerate", "60" },
{ "anisotropy_enable", "false" },
{ "max_anisotropy", "1" },
{ "max_frames_in_flight", "3" },
/* { "", "" } */
};
constexpr vk::ClearColorValue missingTextureColor = { std::array<float, 4>{ 0.4f, 0.0f, 0.4f, 1.0f } };
constexpr size_t VERTEX_BUFFER_SIZE = 512;
constexpr size_t INDEX_BUFFER_SIZE = 512;
constexpr std::array<const char*, 1> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
/* VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME */
};
// DEBUG
/**
* @brief Which message severities to log in VulkanInstance::debugLog()
*/
constexpr vk::DebugUtilsMessageSeverityFlagsEXT debugMessageSevereties =
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError;
/**
* @brief Which message types to log in VulkanInstance::debugLog()
*/
constexpr vk::DebugUtilsMessageTypeFlagsEXT debugMessageTypes =
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance;
// VALIDATION LAYERS
constexpr std::array<const char*, 1> validationLayers {
"VK_LAYER_KHRONOS_validation",
};
constexpr std::array<vk::ValidationFeatureEnableEXT, 3> validationFeaturesEnable {
vk::ValidationFeatureEnableEXT::eDebugPrintf,
vk::ValidationFeatureEnableEXT::eSynchronizationValidation,
vk::ValidationFeatureEnableEXT::eBestPractices
};
constexpr vk::ValidationFeaturesEXT validationFeatures {
.enabledValidationFeatureCount = static_cast<uint32_t>(validationFeaturesEnable.size()),
.pEnabledValidationFeatures = validationFeaturesEnable.data(),
};
} // namespace gz::vlk::setting