mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
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:
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, ¤tDescriptorSet, 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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user