mirror of
https://github.com/love2d/love.git
synced 2026-08-17 19:23:38 +02:00
vulkan: add support for uniform texture arrays
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user