vulkan: add support for uniform texture arrays

This commit is contained in:
niki
2022-09-11 13:02:38 +02:00
parent 294761713f
commit ef80e11b4d
4 changed files with 90 additions and 97 deletions
-15
View File
@@ -55,11 +55,6 @@ const VkDevice Graphics::getDevice() const
return device; return device;
} }
const VkPhysicalDevice Graphics::getPhysicalDevice() const
{
return physicalDevice;
}
const VmaAllocator Graphics::getVmaAllocator() const const VmaAllocator Graphics::getVmaAllocator() const
{ {
return vmaAllocator; return vmaAllocator;
@@ -2072,16 +2067,6 @@ std::set<Shader*> &Graphics::getUsedShadersInFrame()
return usedShadersInFrame; return usedShadersInFrame;
} }
const OptionalDeviceFeatures &Graphics::getOptionalDeviceFeatures() const
{
return optionalDeviceFeatures;
}
const OptionalDeviceExtensionFunctions &Graphics::getExtensionFunctions() const
{
return ext;
}
VkSampler Graphics::getCachedSampler(const SamplerState &samplerState) VkSampler Graphics::getCachedSampler(const SamplerState &samplerState)
{ {
auto it = samplers.find(samplerState); auto it = samplers.find(samplerState);
+7 -11
View File
@@ -122,7 +122,7 @@ struct GraphicsPipelineConfiguration
{ {
VkRenderPass renderPass; VkRenderPass renderPass;
VertexAttributes vertexAttributes; VertexAttributes vertexAttributes;
Shader* shader = nullptr; Shader *shader = nullptr;
bool wireFrame; bool wireFrame;
BlendState blendState; BlendState blendState;
ColorChannelMask colorChannelMask; ColorChannelMask colorChannelMask;
@@ -168,10 +168,10 @@ struct SamplerStateHasher
struct BatchedDrawBuffers struct BatchedDrawBuffers
{ {
StreamBuffer* vertexBuffer1; StreamBuffer *vertexBuffer1;
StreamBuffer* vertexBuffer2; StreamBuffer *vertexBuffer2;
StreamBuffer* indexBuffer; StreamBuffer *indexBuffer;
StreamBuffer* constantColorBuffer; StreamBuffer *constantColorBuffer;
~BatchedDrawBuffers() ~BatchedDrawBuffers()
{ {
@@ -231,7 +231,6 @@ public:
const char *getName() const override; const char *getName() const override;
const VkDevice getDevice() const; const VkDevice getDevice() const;
const VkPhysicalDevice getPhysicalDevice() const;
const VmaAllocator getVmaAllocator() const; const VmaAllocator getVmaAllocator() const;
// implementation for virtual functions // implementation for virtual functions
@@ -282,14 +281,11 @@ public:
const VkDeviceSize getMinUniformBufferOffsetAlignment() const; const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
graphics::Texture *getDefaultTexture() const; graphics::Texture *getDefaultTexture() const;
VkSampler getCachedSampler(const SamplerState&); VkSampler getCachedSampler(const SamplerState &);
void setComputeShader(Shader*); void setComputeShader(Shader *);
std::set<Shader*> &getUsedShadersInFrame(); std::set<Shader*> &getUsedShadersInFrame();
const OptionalDeviceFeatures &getOptionalDeviceFeatures() const;
const OptionalDeviceExtensionFunctions &getExtensionFunctions() const;
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
protected: protected:
+81 -71
View File
@@ -159,7 +159,6 @@ Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
{ {
auto gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS); auto gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
vgfx = dynamic_cast<Graphics*>(gfx); vgfx = dynamic_cast<Graphics*>(gfx);
auto &optionalDeviceFeaures = vgfx->getOptionalDeviceFeatures();
loadVolatile(); loadVolatile();
} }
@@ -175,6 +174,7 @@ bool Shader::loadVolatile()
calculateUniformBufferSizeAligned(); calculateUniformBufferSizeAligned();
createDescriptorSetLayout(); createDescriptorSetLayout();
createPipelineLayout(); createPipelineLayout();
createDescriptorPoolSizes();
createStreamBuffers(); createStreamBuffers();
descriptorSetsVector.resize(vgfx->getNumImagesInFlight()); descriptorSetsVector.resize(vgfx->getNumImagesInFlight());
currentFrame = 0; currentFrame = 0;
@@ -230,7 +230,7 @@ VkPipeline Shader::getComputePipeline() const
return computePipeline; return computePipeline;
} }
static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* texture, bool sampler) static VkDescriptorImageInfo *createDescriptorImageInfo(graphics::Texture *texture, bool sampler)
{ {
auto vkTexture = (Texture*)texture; auto vkTexture = (Texture*)texture;
@@ -270,10 +270,6 @@ void Shader::newFrame(uint32_t frameIndex)
currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
std::vector<VkWriteDescriptorSet> descriptorWrite{};
std::vector<VkDescriptorImageInfo*> imageInfos;
// update everything other than uniform buffers // update everything other than uniform buffers
for (const auto &[key, val] : uniformInfos) { for (const auto &[key, val] : uniformInfos) {
// fixme: other types. // fixme: other types.
@@ -284,14 +280,25 @@ void Shader::newFrame(uint32_t frameIndex)
write.dstBinding = val.location; write.dstBinding = val.location;
write.dstArrayElement = 0; write.dstArrayElement = 0;
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write.descriptorCount = 1; write.descriptorCount = val.count;
VkDescriptorImageInfo* imageInfo = createDescriptorImageInfo(val.textures[0], true); // fixme: arrays std::vector<VkDescriptorImageInfo> imageInfos;
imageInfos.push_back(imageInfo);
write.pImageInfo = imageInfo; for (int i = 0; i < val.count; i++)
{
auto vkTexture = dynamic_cast<Texture*>(val.textures[i]);
descriptorWrite.push_back(write); VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = vkTexture->getImageLayout();
imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle();
imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle();
imageInfos.push_back(imageInfo);
}
write.pImageInfo = imageInfos.data();
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
} }
if (val.baseType == UNIFORM_STORAGETEXTURE) { if (val.baseType == UNIFORM_STORAGETEXTURE) {
VkWriteDescriptorSet write{}; VkWriteDescriptorSet write{};
@@ -300,20 +307,26 @@ void Shader::newFrame(uint32_t frameIndex)
write.dstBinding = val.location; write.dstBinding = val.location;
write.dstArrayElement = 0; write.dstArrayElement = 0;
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
write.descriptorCount = 1; write.descriptorCount = val.count;
VkDescriptorImageInfo* imageInfo = createDescriptorImageInfo(val.textures[0], false); // fixme: arrays std::vector<VkDescriptorImageInfo> imageInfos;
imageInfos.push_back(imageInfo);
write.pImageInfo = imageInfo; for (int i = 0; i < val.count; i++)
descriptorWrite.push_back(write); {
auto vkTexture = dynamic_cast<Texture*>(val.textures[i]);
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = vkTexture->getImageLayout();
imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle();
imageInfos.push_back(imageInfo);
}
write.pImageInfo = imageInfos.data();
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
} }
} }
vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr);
for (const auto imageInfo : imageInfos)
delete imageInfo;
} }
void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint) void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint)
@@ -334,7 +347,6 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind
memcpy(dst, &builtinData, sizeof(builtinData)); memcpy(dst, &builtinData, sizeof(builtinData));
} }
// additional data is always added onto the last stream buffer in the current frame
auto currentStreamBuffer = streamBuffers.at(currentFrame).back(); auto currentStreamBuffer = streamBuffers.at(currentFrame).back();
auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned); auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned);
@@ -928,6 +940,30 @@ void Shader::createPipelineLayout()
} }
} }
void Shader::createDescriptorPoolSizes()
{
if (!localUniformData.empty())
{
VkDescriptorPoolSize size{};
size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
size.descriptorCount = 1;
descriptorPoolSizes.push_back(size);
}
for (const auto &[key, val] : uniformInfos)
{
VkDescriptorPoolSize size{};
auto type = Vulkan::getDescriptorType(val.baseType);
if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
continue;
}
size.type = type;
size.descriptorCount = 1;
descriptorPoolSizes.push_back(size);
}
}
void Shader::createStreamBuffers() void Shader::createStreamBuffers()
{ {
const auto numImagesInFlight = vgfx->getNumImagesInFlight(); const auto numImagesInFlight = vgfx->getNumImagesInFlight();
@@ -938,29 +974,25 @@ void Shader::createStreamBuffers()
void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture)
{ {
// if the shader doesn't actually use these textures they might get optimized out std::array<graphics::Texture*, 3> textures = {
// in that case this function becomes a noop. ytexture, cbtexture, crtexture
if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y] != nullptr) };
{
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0]; std::array<BuiltinUniform, 3> builtIns = {
ytexture->retain(); BUILTIN_TEXTURE_VIDEO_Y,
oldTexture->release(); BUILTIN_TEXTURE_VIDEO_CB,
builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0] = ytexture; BUILTIN_TEXTURE_VIDEO_CR,
} };
if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB] != nullptr)
{ static_assert(textures.size() == builtIns.size());
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0];
cbtexture->retain(); for (size_t i = 0; i < textures.size(); i++)
oldTexture->release(); if (builtinUniformInfo[builtIns[i]] != nullptr)
builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0] = cbtexture; {
} textures[i]->retain();
if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR] != nullptr) builtinUniformInfo[builtIns[i]]->textures[0]->release();
{ builtinUniformInfo[builtIns[i]]->textures[0] = textures[i];
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR]->textures[0]; }
crtexture->retain();
oldTexture->release();
builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR]->textures[0] = crtexture;
}
} }
bool Shader::hasUniform(const std::string &name) const bool Shader::hasUniform(const std::string &name) const
@@ -972,9 +1004,8 @@ void Shader::setMainTex(graphics::Texture *texture)
{ {
if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr) if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr)
{ {
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0];
texture->retain(); texture->retain();
oldTexture->release(); builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]->release();
builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture; builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture;
} }
} }
@@ -983,32 +1014,11 @@ VkDescriptorSet Shader::allocateDescriptorSet()
{ {
if (freeDescriptorSets.empty()) if (freeDescriptorSets.empty())
{ {
// fixme: we can optimize this, since sizes should never change for a given shader.
std::vector<VkDescriptorPoolSize> sizes;
VkDescriptorPoolSize size{};
size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
size.descriptorCount = 1;
sizes.push_back(size);
for (const auto &[key, val] : uniformInfos)
{
VkDescriptorPoolSize size{};
auto type = Vulkan::getDescriptorType(val.baseType);
if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
continue;
}
size.type = type;
size.descriptorCount = 1;
sizes.push_back(size);
}
VkDescriptorPoolCreateInfo createInfo{}; VkDescriptorPoolCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
createInfo.maxSets = DESCRIPTOR_POOL_SIZE; createInfo.maxSets = DESCRIPTOR_POOL_SIZE;
createInfo.poolSizeCount = static_cast<uint32_t>(sizes.size()); createInfo.poolSizeCount = static_cast<uint32_t>(descriptorPoolSizes.size());
createInfo.pPoolSizes = sizes.data(); createInfo.pPoolSizes = descriptorPoolSizes.data();
VkDescriptorPool pool; VkDescriptorPool pool;
if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS)
@@ -1019,7 +1029,7 @@ VkDescriptorSet Shader::allocateDescriptorSet()
VkDescriptorSetAllocateInfo allocInfo{}; VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPools.back(); allocInfo.descriptorPool = pool;
allocInfo.descriptorSetCount = DESCRIPTOR_POOL_SIZE; allocInfo.descriptorSetCount = DESCRIPTOR_POOL_SIZE;
allocInfo.pSetLayouts = layouts.data(); allocInfo.pSetLayouts = layouts.data();
+2
View File
@@ -74,6 +74,7 @@ private:
void compileShaders(); void compileShaders();
void createDescriptorSetLayout(); void createDescriptorSetLayout();
void createPipelineLayout(); void createPipelineLayout();
void createDescriptorPoolSizes();
void createStreamBuffers(); void createStreamBuffers();
void buildLocalUniforms( void buildLocalUniforms(
spirv_cross::Compiler &comp, spirv_cross::Compiler &comp,
@@ -89,6 +90,7 @@ private:
VkDescriptorSetLayout descriptorSetLayout; VkDescriptorSetLayout descriptorSetLayout;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
// we don't know how much memory we need per frame for the uniform buffer descriptors // we don't know how much memory we need per frame for the uniform buffer descriptors
// we keep a vector of stream buffers per frame in flight // we keep a vector of stream buffers per frame in flight