fixed qPriority memory misuse

This commit is contained in:
matthias@arch 2022-11-10 16:58:59 +01:00
parent d1407a839b
commit c21c99d989

View File

@ -6,12 +6,12 @@
#include "vulkan_util.hpp"
#include <gz-util/log.hpp>
#include <gz-util/util/regex.hpp>
#include <gz-util/util/string_conversion.hpp>
#include <gz-util/regex.hpp>
#include <gz-util/string/conversion.hpp>
#include <iterator>
#include <memory>
#include <stop_token>
#include <utility>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_enums.hpp>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
@ -27,6 +27,14 @@
#define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#define VULKAN_INSTANCE_SWAP_CHAIN_AS_TRANSFER_DST
#ifdef VULKAN_INSTANCE_SWAP_CHAIN_AS_TRANSFER_DST
#elif defined VULKAN_INSTANCE_SWAP_CHAIN_AS_RENDER_TARGET
#else
static_assert(false, "either VULKAN_INSTANCE_SWAP_CHAIN_AS_TRANSFER_DST or VULKAN_INSTANCE_SWAP_CHAIN_AS_RENDER_TARGET has to be defined");
#endif
namespace gz::vlk {
using std::uint32_t;
@ -52,6 +60,7 @@ using std::uint32_t;
.pUserData = nullptr,
};
//
//
// IMPLEMENTATION OF VULKANINSTANCE
//
@ -63,9 +72,6 @@ using std::uint32_t;
throw std::runtime_error("Vulkan not supported.");
}
VulkanInstance::registerObjectUsingVulkan("VulkanInstance",
&instance, &physicalDevice, &device, &graphicsQ, &presentQ, &transferQ, &commandPoolGraphics, &commandPoolTransfer, &surface, &swapChain,
&scImages, &scImageViews, &commandBuffersBegin, &commandBuffersEnd);
createInstance();
setupDebugMessenger();
createSurface();
@ -83,9 +89,9 @@ using std::uint32_t;
/* createDescriptorPool(); */
/* createDescriptorSets(); // after UniformBuffers */
for (auto& obj : VulkanInstance::objectsUsingVulkan) {
obj->updateHandles();
}
VulkanInstance::registerObjectUsingVulkan("VulkanInstance",
&instance, &physicalDevice, &device, &graphicsQ, &presentQ, &transferQ, &commandPoolGraphics, &commandPoolTransfer, &surface, &swapChain,
&scImages, &scImageViews, &commandBuffersBegin, &commandBuffersEnd);
}
@ -166,30 +172,17 @@ using std::uint32_t;
throw getVkException(result, "Failed to begin clear command buffer", "VulkanInstance::beginFrameDraw");
}
// transition to transfer dst layout
transitionImageLayout(scImages[imageIndex], scImageFormat, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal, &commandBuffersBegin[currentFrame]);
vk::ImageMemoryBarrier2 imageBarrier {
.srcStageMask = vk::PipelineStageFlagBits2::eNone,
.srcAccessMask = vk::AccessFlagBits2::eNone,
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
.oldLayout = vk::ImageLayout::eUndefined,
.newLayout = vk::ImageLayout::eTransferDstOptimal,
.image = scImages[imageIndex],
.subresourceRange {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
}
};
vk::DependencyInfo depI = getDepInfo(imageBarrier);
commandBuffersBegin[currentFrame].pipelineBarrier2(depI);
#ifdef VULKAN_INSTANCE_SWAP_CHAIN_AS_TRANSFER_DST
vk::ImageLayout targetLayout = vk::ImageLayout::eTransferDstOptimal;
#elif defined VULKAN_INSTANCE_SWAP_CHAIN_AS_RENDER_TARGET
vk::ImageLayout targetLayout = vk::ImageLayout::eColorAttachmentOptimal;
#endif
transitionImageLayout(scImages[imageIndex], scImageFormat, vk::ImageLayout::eUndefined, targetLayout, &commandBuffersBegin[currentFrame]);
result = commandBuffersBegin[currentFrame].end();
if (result != vk::Result::eSuccess) {
vLog.error("Failed to record clear command buffer", "VkResult:", result);
throw getVkException(result, "Failed to record 2D - command buffer", "VulkanInstance::beginFrameDraw");
throw getVkException(result, "Failed to record command buffer", "VulkanInstance::beginFrameDraw");
}
commandBuffersToSubmitThisFrame.push_back(commandBuffersBegin[currentFrame]);
@ -204,8 +197,13 @@ using std::uint32_t;
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to begin command buffer", "VulkanInstance::endFrameDraw");
}
#ifdef VULKAN_INSTANCE_SWAP_CHAIN_AS_TRANSFER_DST
vk::ImageLayout currentLayout = vk::ImageLayout::eTransferDstOptimal;
#elif defined VULKAN_INSTANCE_SWAP_CHAIN_AS_RENDER_TARGET
vk::ImageLayout currentLayout = vk::ImageLayout::eColorAttachmentOptimal;
#endif
// transition to present layout
transitionImageLayout(scImages[imageIndex], scImageFormat, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::ePresentSrcKHR, &commandBuffersEnd[currentFrame]);
transitionImageLayout(scImages[imageIndex], scImageFormat, currentLayout, vk::ImageLayout::ePresentSrcKHR, &commandBuffersEnd[currentFrame]);
result = commandBuffersEnd[currentFrame].end();
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to record command buffer", "VulkanInstance::endFrameDraw");
@ -274,6 +272,34 @@ using std::uint32_t;
}
void VulkanInstance::copyToDeviceBuffer(const void* srcData, vk::DeviceSize srcSize, vk::Buffer& dstBuffer, MemoryInfo& dstMemory, uint32_t dstOffset) {
// create staging buffer
vk::Buffer stagingBuffer;
MemoryInfo stagingBufferMemory;
createBuffer(srcSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory);
// fill staging buffer
void* stagingMemory;
vk::Result result = device.mapMemory(stagingBufferMemory.memory, stagingBufferMemory.offset, srcSize, NO_MEM_FLAGS, &stagingMemory);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to map staging buffer for vertices", "VulkanInstance::copyToDeviceBuffer");
}
memcpy(stagingMemory, srcData, srcSize);
device.unmapMemory(stagingBufferMemory.memory);
// copy to device local memory
vk::CommandBuffer cmdBuffer = beginSingleTimeCommands(POOL_TRANSFER);
vk::BufferCopy copyRegion {
.srcOffset = 0,
.dstOffset = dstOffset,
.size = srcSize,
};
cmdBuffer.copyBuffer(stagingBuffer, dstBuffer, copyRegion);
endSingleTimeCommands(cmdBuffer, POOL_TRANSFER);
destroyBuffer(stagingBuffer, stagingBufferMemory);
vLog.log0("copyToDeviceBuffer: copied data at", srcData, "of size", srcSize, "to dstBuffer");
}
vk::CommandBuffer VulkanInstance::beginSingleTimeCommands(InstanceCommandPool commandPool) {
vk::CommandBufferAllocateInfo allocI {
.level = vk::CommandBufferLevel::ePrimary,
@ -336,44 +362,6 @@ using std::uint32_t;
}
void VulkanInstance::loadModel(const std::string& path, VerticesAndIndices<uint32_t>& model) {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string warnings, errors;
if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warnings, &errors, path.c_str())) {
vLog.warning("Warning from tinyobj::LoadObj: ", warnings);
throw gz::Exception("Error loading obj: " + errors, "loadModel");
}
if (!warnings.empty()) {
vLog.warning("Warning from tinyobj::LoadObj: ", warnings);
}
std::unordered_map<Vertex3D, uint32_t> uniqueVertices;
for (const auto& shape : shapes) {
for (const auto& index : shape.mesh.indices) {
Vertex3D vertex;
vertex.pos = {
attrib.vertices[3 * index.vertex_index + 0],
attrib.vertices[3 * index.vertex_index + 1],
attrib.vertices[3 * index.vertex_index + 2]
};
vertex.texCoord = {
attrib.vertices[2 * index.texcoord_index + 0],
// obj: y = 0 means bottom, vulkan: y = 0 means top
1.0f - attrib.vertices[2 * index.texcoord_index + 1],
};
vertex.color = { 1.0f, 1.0f, 1.0f };
if (!uniqueVertices.contains(vertex)) {
uniqueVertices.insert({ vertex, model.vertices.size() });
model.vertices.push_back(vertex);
}
/* model.vertices.push_back(vertex); */
model.indices.push_back(uniqueVertices[vertex]);
}
}
}
// PUBLIC INTERFACE: CREATION AND DESTRUCTION
// COMMAND BUFFER
void VulkanInstance::createCommandBuffers(std::vector<vk::CommandBuffer>& commandBuffers) {
@ -397,7 +385,7 @@ using std::uint32_t;
// GRAPHICS PIPELINE
template<VertexType VertexT>
void VulkanInstance::createGraphicsPipeline(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline) {
void VulkanInstance::createGraphicsPipeline(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts, const std::vector<vk::PushConstantRange>& pushConstantRanges, bool useDepthStencil, Pipeline& pipeline) {
// 1) sanity checks
if (pipelineCI.pStages == nullptr) {
throw VkUserError("pStages is nullptr", "VulkanInstance::createGraphicsPipeline");
@ -406,7 +394,32 @@ using std::uint32_t;
throw VkUserError("renderPass is VK_NULL_HANDLE", "VulkanInstance::createGraphicsPipeline");
}
// 2) construct default create infos
// 2) create layout
vk::PipelineLayoutCreateInfo pipelineLayoutCI;
// TODO
/* pipelineLayoutCI.setPushConstantRanges() */
if (pushConstantRanges.size() > 0) {
pipelineLayoutCI.setPushConstantRanges(pushConstantRanges);
}
if (descriptorSetLayouts.size() > 0) {
pipelineLayoutCI.setSetLayouts(descriptorSetLayouts);
}
VkPipelineLayoutCreateInfo pipelineLayoutCI2 = static_cast<VkPipelineLayoutCreateInfo>(pipelineLayoutCI);
vLog.log0("createGraphicsPipeline: ", pipelineLayoutCI2.setLayoutCount);
vk::Result result = device.createPipelineLayout(&pipelineLayoutCI, nullptr, &pipeline.layout);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to create pipeline layout", "VulkanInstance::createGraphicsPipeline");
}
vLog.log0("createGraphicsPipeline: created layout: ( descriptorSetLayouts:", descriptorSetLayouts.size(), ")");
vLog.log0("createGraphicsPipeline:", pipelineLayoutCI.setLayoutCount);
pipelineCI.setLayout(pipeline.layout);
// 3) construct default create infos
// default vertexInputStateCI
vk::VertexInputBindingDescription bindingD = VertexT::getBindingDescription();
// array<vk::VertexInputAttributeDescription>
@ -512,20 +525,6 @@ using std::uint32_t;
/* .back = {}, */
};
vk::PipelineLayoutCreateInfo pipelineLayoutCI;
// TODO
/* pipelineLayoutCI.setPushConstantRanges() */
if (descriptorSetLayouts != nullptr) {
pipelineLayoutCI.setSetLayouts(*descriptorSetLayouts);
}
vk::Result result = device.createPipelineLayout(&pipelineLayoutCI, nullptr, &pipeline.layout);
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Failed to create pipeline layout", "VulkanInstance::createGraphicsPipeline");
}
pipelineCI.setLayout(pipeline.layout);
if (pipelineCI.pVertexInputState == nullptr) { pipelineCI.setPVertexInputState(&vertexInputStateCI); }
if (pipelineCI.pInputAssemblyState == nullptr) { pipelineCI.setPInputAssemblyState(&inputAssemblyStateCI); }
if (pipelineCI.pViewportState == nullptr) { pipelineCI.setPViewportState(&viewportStateCI); }
@ -541,10 +540,10 @@ using std::uint32_t;
throw getVkException(result, "Could not create graphics pipeline", "createGraphicsPipeline");
}
vLog.log0("createGraphicsPipeline: Created graphics pipeline.");
vLog.log0("createGraphicsPipeline: Created graphics pipeline ( useDepthStencil:", useDepthStencil, ")" );
}
template void VulkanInstance::createGraphicsPipeline<Vertex2D>(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline);
template void VulkanInstance::createGraphicsPipeline<Vertex3D>(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>* descriptorSetLayouts, bool useDepthStencil, Pipeline& pipeline);
template void VulkanInstance::createGraphicsPipeline<Vertex2D>(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts, const std::vector<vk::PushConstantRange>& pushConstantRanges, bool useDepthStencil, Pipeline& pipeline);
template void VulkanInstance::createGraphicsPipeline<Vertex3D>(vk::GraphicsPipelineCreateInfo&& pipelineCI, const std::vector<vk::DescriptorSetLayout>& descriptorSetLayouts, const std::vector<vk::PushConstantRange>& pushConstantRanges, bool useDepthStencil, Pipeline& pipeline);
// SHADER MODULE
@ -742,7 +741,7 @@ using std::uint32_t;
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Could not create descriptorSetLayout", "VulkanInstance::createDescriptorSetLayout");
}
vLog.log0("createDescriptorSetLayout: Created descriptor set layout with", bindings.size(), "bindings");
vLog.log0("createDescriptorSetLayout: Created descriptor set layout with the following bindings:", bindings);
}
@ -838,7 +837,7 @@ using std::uint32_t;
// IMAGE VIEW
void VulkanInstance::createImageView(vk::Format format, vk::Image& image, vk::ImageView& imageView, vk::ImageAspectFlags aspectFlags) {
void VulkanInstance::createImageView(vk::Format format, const vk::Image& image, vk::ImageView& imageView, vk::ImageAspectFlags aspectFlags) {
vk::ImageViewCreateInfo imageViewCI {
.image = image,
.viewType = vk::ImageViewType::e2D,
@ -861,6 +860,7 @@ using std::uint32_t;
if (result != vk::Result::eSuccess) {
throw getVkException(result, "Could not create image view", "VulkanInstance::createImageViews");
}
vLog.log0("createImageView: Created image view with format", format);
}
@ -955,13 +955,13 @@ using std::uint32_t;
barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite;
commandPool = POOL_TRANSFER;
}
else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and
newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) {
barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer;
barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader;
barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead;
commandPool = POOL_GRAPHICS;
else if (oldLayout == vk::ImageLayout::eUndefined and
newLayout == vk::ImageLayout::eColorAttachmentOptimal) {
barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone;
barrier.srcAccessMask = vk::AccessFlagBits2::eNone;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput;
barrier.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite;
commandPool = POOL_TRANSFER;
}
else if (oldLayout == vk::ImageLayout::eShaderReadOnlyOptimal and
newLayout == vk::ImageLayout::eTransferDstOptimal) {
@ -971,6 +971,14 @@ using std::uint32_t;
barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite;
commandPool = POOL_GRAPHICS;
}
else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and
newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) {
barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer;
barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader;
barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead;
commandPool = POOL_GRAPHICS;
}
else if (oldLayout == vk::ImageLayout::eTransferDstOptimal and
newLayout == vk::ImageLayout::ePresentSrcKHR) {
barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer;
@ -979,6 +987,22 @@ using std::uint32_t;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput;
commandPool = POOL_GRAPHICS;
}
else if (oldLayout == vk::ImageLayout::eColorAttachmentOptimal and
newLayout == vk::ImageLayout::ePresentSrcKHR) {
barrier.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput;
barrier.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite;
barrier.dstAccessMask = vk::AccessFlagBits2::eMemoryRead;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput;
commandPool = POOL_GRAPHICS;
}
else if (oldLayout == vk::ImageLayout::eColorAttachmentOptimal and
newLayout == vk::ImageLayout::eTransferSrcOptimal) {
barrier.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput;
barrier.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite;
barrier.dstAccessMask = vk::AccessFlagBits2::eTransferRead;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer;
commandPool = POOL_GRAPHICS;
}
else {
throw VkUserError(std::string("Unsupported layout transition") + ::toString(oldLayout) + "->" + ::toString(newLayout), "VulkanInstance::transitionImageLayout");
}
@ -1001,7 +1025,14 @@ using std::uint32_t;
//
// STATIC: DEBUG LOG
//
gz::Log VulkanInstance::vLog("vulkan.log", true, true, "Vulkan", settings::VULKAN_MESSAGE_PREFIX_COLOR, true, settings::VULKAN_MESSAGE_TIME_COLOR);
gz::Log VulkanInstance::vLog(LogCreateInfo {
.logfile = "vulkan.log",
.showLog = true,
.storeLog = true,
.prefix = "Vulkan",
.prefixColor = settings::VULKAN_MESSAGE_PREFIX_COLOR,
.showTime = true,
.timeColor = settings::VULKAN_MESSAGE_TIME_COLOR});
VKAPI_ATTR VkBool32 VKAPI_CALL VulkanInstance::debugLog(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverety,
VkDebugUtilsMessageTypeFlagsEXT messageType,
@ -1389,13 +1420,16 @@ using std::uint32_t;
qFamiliyIndicesSet.insert(qFamilyIndices.transferFamily.value());
}
std::vector<float> qPriorities;
// make sure no reallocation happes as that would invalidate the pointers
qPriorities.reserve(qFamiliyIndicesSet.size());
std::vector<vk::DeviceQueueCreateInfo> deviceQueueCI;
for (uint32_t index : qFamiliyIndicesSet) {
deviceQueueCI.push_back(vk::DeviceQueueCreateInfo());
deviceQueueCI.back().queueFamilyIndex = index;
deviceQueueCI.back().queueCount = 1;
float qPriority = 1.0f;
deviceQueueCI.back().pQueuePriorities = &qPriority;
qPriorities.emplace_back(1.0f);
deviceQueueCI.back().pQueuePriorities = &(qPriorities.back());
}
PhysicalDeviceFeatures enabledFeatures = getRequiredDeviceFeatures();
@ -1719,41 +1753,46 @@ using std::uint32_t;
// HANDLE OWNERSHIP
bool VulkanInstance::lastColorWhite;
std::vector<std::unique_ptr<ObjectUsingVulkanBase>> VulkanInstance::objectsUsingVulkan;
std::set<uint64_t> VulkanInstance::foundHandles;
const std::regex reAddress(R"(0x[0-9a-f]+)");
const std::regex reAddress(R"(handle = (0x[0-9a-f]+))");
std::string VulkanInstance::handleOwnerString(100, ' '); // reserve size 100
//
void VulkanInstance::getHandleOwnerString(std::string_view message) {
handleOwnerString.clear();
re::svmatch match;
if (re::regex_search(message, match, reAddress)) {
handleOwnerString = "Handle ownerships: [ ";
bool foundHandle = false;
for (auto it = match.begin(); it != match.end(); it++) {
uint64_t address;
std::stringstream ss;
ss << std::hex << it->str();
ss >> address;
for (auto& obj : objectsUsingVulkan) {
/* vLog(address, obj.handles); */
if (obj->contains(address)) {
handleOwnerString += it->str() + " - " + obj->getName();
address = 0;
foundHandle = true;
}
/* for (auto& obj : objectsUsingVulkan) { vLog(obj); }; */
handleOwnerString = "Handle ownerships: [ ";
foundHandles.clear();
while (re::regex_search(message, match, reAddress)) {
/* vLog("getHandleOwnerString: found", match.size(), "addresses"); */
uint64_t address;
std::stringstream ss;
ss << std::hex << match.str(1);
ss >> address;
// filter duplicates
if (foundHandles.contains(address)) {
goto stopOwnerSearch;
}
for (auto& obj : objectsUsingVulkan) {
if (obj->contains(address)) {
handleOwnerString += match.str(1) + " - " + obj->getName() + ", ";
foundHandles.insert(address);
address = 0;
goto stopOwnerSearch;
}
if (address != 0) {
handleOwnerString += "Unknown";
}
handleOwnerString += ", ";
}
if (foundHandle) {
handleOwnerString.erase(handleOwnerString.size()-2);
handleOwnerString += " ]";
}
else {
handleOwnerString.clear();
}
// if not found
handleOwnerString += match.str(1) + " - Unknown, ";
stopOwnerSearch:
message = std::string_view(message.begin() + match.position() + match.length(), message.end());
} // while
if (foundHandles.size() > 0) {
handleOwnerString.erase(handleOwnerString.size() - 2);
handleOwnerString += " ]";
}
else {
handleOwnerString.clear();
}
}