vulkan: remove dep on VK_KHR_push_descriptor

It's not sure if this extension is supported everywhere
This commit uses normal descriptor pools, sets and writes,
which are all availabel in base vulkan.
This commit is contained in:
niki
2022-08-19 16:44:59 +02:00
parent f4ece69307
commit be8778b4eb
6 changed files with 104 additions and 39 deletions
-13
View File
@@ -36,9 +36,6 @@ const std::vector<const char*> validationLayers = {
const std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_push_descriptor.html
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME
};
#ifdef NDEBUG
@@ -551,10 +548,6 @@ graphics::Texture* Graphics::getDefaultTexture() const {
return dynamic_cast<graphics::Texture*>(standardTexture.get());
}
const PFN_vkCmdPushDescriptorSetKHR Graphics::getVkCmdPushDescriptorSetKHRFunctionPointer() const {
return vkCmdPushDescriptorSet;
}
VkCommandBuffer Graphics::getDataTransferCommandBuffer() {
return dataTransferCommandBuffers.at(currentFrame);
}
@@ -861,12 +854,6 @@ void Graphics::createLogicalDevice() {
vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
vkCmdPushDescriptorSet = (PFN_vkCmdPushDescriptorSetKHR) vkGetDeviceProcAddr(device, "vkCmdPushDescriptorSetKHR");
if (!vkCmdPushDescriptorSet) {
// fixme: how widely adopted is this extension?
throw love::Exception("could not get a valid function pointer for vkCmdPushDescriptorSetKHR");
}
}
void Graphics::initVMA() {
-2
View File
@@ -139,7 +139,6 @@ public:
void queueCleanUp(std::function<void()> cleanUp);
uint32_t getNumImagesInFlight() const;
const PFN_vkCmdPushDescriptorSetKHR getVkCmdPushDescriptorSetKHRFunctionPointer() const;
const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
graphics::Texture* getDefaultTexture() const;
VkSampler getCachedSampler(const SamplerState&);
@@ -220,7 +219,6 @@ private:
std::vector<VkFence> inFlightFences;
std::vector<VkFence> imagesInFlight;
VkDeviceSize minUniformBufferOffsetAlignment = 0;
PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSet = nullptr;
size_t currentFrame = 0;
uint32_t imageIndex = 0;
bool framebufferResized = false;
+74 -21
View File
@@ -118,6 +118,7 @@ static const TBuiltInResource defaultTBuiltInResource = {
};
static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16;
static const uint32_t DESCRIPTOR_POOL_SIZE = 32;
static VkShaderStageFlagBits getStageBit(ShaderStageType type) {
switch (type) {
@@ -159,8 +160,11 @@ bool Shader::loadVolatile() {
createDescriptorSetLayout();
createPipelineLayout();
createStreamBuffers();
descriptorSetsVector.resize(((Graphics*)gfx)->getNumImagesInFlight());
currentFrame = 0;
count = 0;
currentUsedUniformStreamBuffersCount = 0;
currentUsedDescriptorSetsCount = 0;
currentAllocatedDescriptorSets = DESCRIPTOR_POOL_SIZE;
return true;
}
@@ -171,7 +175,10 @@ void Shader::unloadVolatile() {
}
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
gfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout](){
gfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools](){
for (const auto pool : descriptorPools) {
vkDestroyDescriptorPool(device, pool, nullptr);
}
for (const auto shaderModule : shaderModules) {
vkDestroyShaderModule(device, shaderModule, nullptr);
}
@@ -186,6 +193,8 @@ void Shader::unloadVolatile() {
shaderModules.clear();
shaderStages.clear();
streamBuffers.clear();
descriptorPools.clear();
descriptorSetsVector.clear();
}
const std::vector<VkPipelineShaderStageCreateInfo>& Shader::getShaderStages() const {
@@ -212,7 +221,9 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
// detect wether a new frame has begun
if (currentFrame != frameIndex) {
currentFrame = frameIndex;
count = 0;
currentUsedUniformStreamBuffersCount = 0;
currentUsedDescriptorSetsCount = 0;
// we needed more memory last frame, let's collapse all buffers into a single one.
if (streamBuffers.at(currentFrame).size() > 1) {
@@ -223,7 +234,7 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
}
streamBuffers.at(currentFrame).clear();
streamBuffers.at(currentFrame).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, newSize));
}
}
// no collapse necessary, can just call nextFrame to reset the current (only) streambuffer
else {
streamBuffers.at(currentFrame).at(0)->nextFrame();
@@ -231,14 +242,18 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
}
// still the same frame
else {
auto usedStreamBufferMemory = count * uniformBufferSizeAligned;
auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
if (usedStreamBufferMemory >= streamBuffers.at(currentFrame).back()->getSize()) {
// we ran out of memory in the current frame, need to allocate more.
streamBuffers.at(currentFrame).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
count = 0;
currentUsedUniformStreamBuffersCount = 0;
}
}
if (currentUsedDescriptorSetsCount >= descriptorSetsVector.at(currentFrame).size()) {
descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
}
// additional data is always added onto the last stream buffer in the current frame
auto currentStreamBuffer = streamBuffers.at(currentFrame).back();
@@ -249,16 +264,18 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = (VkBuffer)currentStreamBuffer->getHandle();
bufferInfo.offset = count * uniformBufferSizeAligned;
bufferInfo.offset = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
bufferInfo.range = sizeof(BuiltinUniformData);
VkDescriptorSet currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
std::vector<VkWriteDescriptorSet> descriptorWrite{};
// uniform buffer update always happens
// (are there cases without ubos at all?)
VkWriteDescriptorSet uniformWrite{};
uniformWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
uniformWrite.dstSet = 0;
uniformWrite.dstSet = currentDescriptorSet;
uniformWrite.dstBinding = builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW]->location;
uniformWrite.dstArrayElement = 0;
uniformWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
@@ -267,9 +284,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
descriptorWrite.push_back(uniformWrite);
// Vulkan needs the image infos as a pointer.
// we collect them all here to properly free them up
// after the vulkan call.
std::vector<VkDescriptorImageInfo*> imageInfos;
// update everything other than uniform buffers (since that's already taken care of.
@@ -278,7 +292,7 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
if (val.baseType == UNIFORM_SAMPLER) {
VkWriteDescriptorSet write{};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = 0;
write.dstSet = currentDescriptorSet;
write.dstBinding = val.location;
write.dstArrayElement = 0;
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
@@ -295,16 +309,16 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
}
}
vkCmdPushDescriptorSet(
commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout, 0,
static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data());
vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr);
for (const auto imageInfo : imageInfos) {
delete imageInfo;
}
count++;
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &currentDescriptorSet, 0, nullptr);
currentUsedUniformStreamBuffersCount++;
currentUsedDescriptorSetsCount++;
}
Shader::~Shader() {
@@ -614,9 +628,6 @@ void Shader::compileShaders() {
}
void Shader::createDescriptorSetLayout() {
auto vgfx = (Graphics*)gfx;
vkCmdPushDescriptorSet = vgfx->getVkCmdPushDescriptorSetKHRFunctionPointer();
std::vector<VkDescriptorSetLayoutBinding> bindings;
for (auto const& [key, val] : uniformInfos) {
@@ -631,7 +642,6 @@ void Shader::createDescriptorSetLayout() {
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
layoutInfo.pBindings = bindings.data();
@@ -691,6 +701,49 @@ void Shader::setMainTex(graphics::Texture* texture) {
builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture;
}
}
VkDescriptorSet Shader::allocateDescriptorSet() {
if (currentAllocatedDescriptorSets >= DESCRIPTOR_POOL_SIZE) {
// fixme: we can optimize this, since sizes should never change for a given shader.
std::vector<VkDescriptorPoolSize> sizes;
for (const auto& [key, val] : uniformInfos) {
VkDescriptorPoolSize size{};
size.type = Vulkan::getDescriptorType(val.baseType);
size.descriptorCount = 1;
sizes.push_back(size);
}
VkDescriptorPoolCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
createInfo.maxSets = DESCRIPTOR_POOL_SIZE;
createInfo.poolSizeCount = static_cast<uint32_t>(sizes.size());
createInfo.pPoolSizes = sizes.data();
VkDescriptorPool pool;
if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) {
throw love::Exception("failed to create descriptor pool");
}
descriptorPools.push_back(pool);
currentAllocatedDescriptorSets = 0;
}
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPools.back();
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &descriptorSetLayout;
VkDescriptorSet descriptorSet;
if (vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet) != VK_SUCCESS) {
throw love::Exception("failed to allocate descriptor set");
}
currentAllocatedDescriptorSets++;
return descriptorSet;
}
} // vulkan
} // graphics
} // love
+7 -3
View File
@@ -70,8 +70,9 @@ private:
size_t baseoff,
const std::string& basename);
VkDescriptorSet allocateDescriptorSet();
VkDeviceSize uniformBufferSizeAligned;
PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSet;
VkDescriptorSetLayout descriptorSetLayout;
VkPipelineLayout pipelineLayout;
@@ -80,6 +81,9 @@ private:
// we keep a vector of stream buffers per frame in flight
// that gets dynamically increased if more memory is needed
std::vector<std::vector<StreamBuffer*>> streamBuffers;
std::vector<VkDescriptorPool> descriptorPools;
uint32_t currentAllocatedDescriptorSets;
std::vector<std::vector<VkDescriptorSet>> descriptorSetsVector;
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
std::vector<VkShaderModule> shaderModules;
@@ -94,8 +98,8 @@ private:
size_t builtinUniformDataOffset;
uint32_t currentFrame;
// todo: give this variable a better name
uint32_t count;
uint32_t currentUsedUniformStreamBuffersCount;
uint32_t currentUsedDescriptorSetsCount;
};
}
}
+22
View File
@@ -552,6 +552,28 @@ VkSamplerMipmapMode Vulkan::getMipMapMode(SamplerState::MipmapFilterMode mode) {
}
}
VkDescriptorType Vulkan::getDescriptorType(graphics::Shader::UniformType type) {
switch (type) {
case graphics::Shader::UniformType::UNIFORM_FLOAT:
case graphics::Shader::UniformType::UNIFORM_MATRIX:
case graphics::Shader::UniformType::UNIFORM_INT:
case graphics::Shader::UniformType::UNIFORM_UINT:
case graphics::Shader::UniformType::UNIFORM_BOOL:
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
case graphics::Shader::UniformType::UNIFORM_SAMPLER:
return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
case graphics::Shader::UniformType::UNIFORM_STORAGETEXTURE:
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
case graphics::Shader::UniformType::UNIFORM_TEXELBUFFER:
return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
case graphics::Shader::UniformType::UNIFORM_STORAGEBUFFER:
return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
default:
throw love::Exception("unkonwn uniform type");
}
}
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout,
uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) {
VkImageMemoryBarrier barrier{};
+1
View File
@@ -48,6 +48,7 @@ public:
static VkSamplerAddressMode getWrapMode(SamplerState::WrapMode);
static VkCompareOp getCompareOp(CompareMode);
static VkSamplerMipmapMode getMipMapMode(SamplerState::MipmapFilterMode);
static VkDescriptorType getDescriptorType(graphics::Shader::UniformType);
static void cmdTransitionImageLayout(
VkCommandBuffer, VkImage, VkImageLayout oldLayout, VkImageLayout newLayout,