diff --git a/src/modules/graphics/vulkan/Buffer.cpp b/src/modules/graphics/vulkan/Buffer.cpp index 100213d5f..4ba184595 100644 --- a/src/modules/graphics/vulkan/Buffer.cpp +++ b/src/modules/graphics/vulkan/Buffer.cpp @@ -15,6 +15,7 @@ static VkBufferUsageFlags getUsageBit(BufferUsage mode) case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + case BUFFERUSAGE_TEXEL: return VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; default: throw love::Exception("unsupported BufferUsage mode"); } @@ -47,16 +48,27 @@ bool Buffer::loadVolatile() VkBufferCreateInfo bufferInfo{}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = getSize(); - if (dataUsage == BUFFERDATAUSAGE_READBACK) - bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; - else - bufferInfo.usage = getVulkanUsageFlags(usageFlags); + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | getVulkanUsageFlags(usageFlags); VmaAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; - vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo); + auto result = vmaCreateBuffer(allocator, &bufferInfo, &allocCreateInfo, &buffer, &allocation, &allocInfo); + if (result != VK_SUCCESS) + throw love::Exception("failed to create buffer"); + + if (usageFlags & BUFFERUSAGE_TEXEL) + { + VkBufferViewCreateInfo bufferViewInfo{}; + bufferViewInfo.buffer = buffer; + bufferViewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; + bufferViewInfo.format = Vulkan::getVulkanVertexFormat(getDataMember(0).decl.format); + bufferViewInfo.range = VK_WHOLE_SIZE; + + if (vkCreateBufferView(vgfx->getDevice(), &bufferViewInfo, nullptr, &bufferView) != VK_SUCCESS) + throw love::Exception("failed to create texel buffer view"); + } return true; } @@ -69,12 +81,15 @@ void Buffer::unloadVolatile() auto device = vgfx->getDevice(); vgfx->queueCleanUp( - [device=device, allocator=allocator, buffer=buffer, allocation=allocation](){ + [device=device, allocator=allocator, buffer=buffer, allocation=allocation, bufferView=bufferView](){ vkDeviceWaitIdle(device); vmaDestroyBuffer(allocator, buffer, allocation); + if (bufferView) + vkDestroyBufferView(device, bufferView, nullptr); }); buffer = VK_NULL_HANDLE; + bufferView = VK_NULL_HANDLE; } Buffer::~Buffer() @@ -89,8 +104,7 @@ ptrdiff_t Buffer::getHandle() const ptrdiff_t Buffer::getTexelBufferHandle() const { - throw love::Exception("unimplemented Buffer::getTexelBufferHandle"); - return (ptrdiff_t) nullptr; // todo ? + return (ptrdiff_t) bufferView; } void* Buffer::map(MapType map, size_t offset, size_t size) diff --git a/src/modules/graphics/vulkan/Buffer.h b/src/modules/graphics/vulkan/Buffer.h index 1c0311e6c..148b300b4 100644 --- a/src/modules/graphics/vulkan/Buffer.h +++ b/src/modules/graphics/vulkan/Buffer.h @@ -36,6 +36,7 @@ public: private: // todo use a staging buffer for improved performance VkBuffer buffer = VK_NULL_HANDLE; + VkBufferView bufferView = VK_NULL_HANDLE; Graphics *vgfx = nullptr; VmaAllocator allocator; VmaAllocation allocation; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 8bba0a252..b3299c8da 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -270,63 +270,7 @@ void Shader::newFrame(uint32_t frameIndex) currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); - // update everything other than uniform buffers - for (const auto &[key, val] : uniformInfos) { - // fixme: other types. - if (val.baseType == UNIFORM_SAMPLER) { - VkWriteDescriptorSet write{}; - write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.dstSet = currentDescriptorSet; - write.dstBinding = val.location; - write.dstArrayElement = 0; - write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write.descriptorCount = val.count; - - std::vector imageInfos; - - for (int i = 0; i < val.count; i++) - { - auto vkTexture = dynamic_cast(val.textures[i]); - - 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) { - VkWriteDescriptorSet write{}; - write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.dstSet = currentDescriptorSet; - write.dstBinding = val.location; - write.dstArrayElement = 0; - write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - write.descriptorCount = val.count; - - std::vector imageInfos; - - for (int i = 0; i < val.count; i++) - { - auto vkTexture = dynamic_cast(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); - } - } + initDescriptorSet(); } void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint) @@ -409,6 +353,8 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet()); currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); + + initDescriptorSet(); } Shader::~Shader() @@ -465,12 +411,17 @@ static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info) void Shader::updateUniform(const UniformInfo *info, int count) { - if (current == this) + updateUniform(info, count, false); +} + +void Shader::updateUniform(const UniformInfo* info, int count, bool internal) +{ + if (!internal && current == this) Graphics::flushBatchedDrawsGlobal(); if (usesLocalUniformData(info)) memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size()); - else if (info->baseType == UNIFORM_SAMPLER || info->baseType == UNIFORM_STORAGETEXTURE) + if (info->baseType == UNIFORM_SAMPLER || info->baseType == UNIFORM_STORAGETEXTURE) { bool isSampler = info->baseType == UNIFORM_SAMPLER; @@ -495,10 +446,58 @@ void Shader::updateUniform(const UniformInfo *info, int count) write.dstSet = currentDescriptorSet; write.dstBinding = info->location; write.dstArrayElement = 0; - write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + if (isSampler) + write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + else + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; write.descriptorCount = static_cast(count); write.pImageInfo = imageInfos.data(); + vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); + } + if (info->baseType == UNIFORM_STORAGEBUFFER) + { + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = currentDescriptorSet; + write.dstBinding = info->location; + write.dstArrayElement = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + write.descriptorCount = info->count; + + std::vector bufferInfos; + + for (int i = 0; i < info->count; i++) + { + VkDescriptorBufferInfo bufferInfo{}; + bufferInfo.buffer = (VkBuffer)info->buffers[i]->getHandle();; + bufferInfo.offset = 0; + bufferInfo.range = info->buffers[i]->getSize(); + + bufferInfos.push_back(bufferInfo); + } + + write.pBufferInfo = bufferInfos.data(); + + vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); + } + if (info->baseType == UNIFORM_TEXELBUFFER) + { + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstSet = currentDescriptorSet; + write.dstBinding = info->location; + write.dstArrayElement = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + write.descriptorCount = info->count; + + std::vector bufferViews; + + for (int i = 0; i < info->count; i++) + bufferViews.push_back((VkBufferView)info->buffers[i]->getTexelBufferHandle()); + + write.pTexelBufferView = bufferViews.data(); + vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); } } @@ -515,6 +514,18 @@ void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, } } +void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) +{ + for (int i = 0; i < count; i++) + { + auto oldBuffer = info->buffers[i]; + info->buffers[i] = buffers[i]; + info->buffers[i]->retain(); + if (oldBuffer) + oldBuffer->release(); + } +} + void Shader::calculateUniformBufferSizeAligned() { auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment(); @@ -525,6 +536,13 @@ void Shader::calculateUniformBufferSizeAligned() uniformBufferSizeAligned = factor * minAlignment; } +void Shader::initDescriptorSet() +{ + for (const auto &[key, val] : uniformInfos) + if (Vulkan::getDescriptorType(val.baseType) != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) + updateUniform(&val, val.count, true); +} + void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename) { using namespace spirv_cross; @@ -880,6 +898,12 @@ void Shader::createDescriptorSetLayout() { std::vector bindings; + VkShaderStageFlags stageFlags; + if (isCompute) + stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + else + stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + for (auto const &[key, val] : uniformInfos) { auto type = Vulkan::getDescriptorType(val.baseType); @@ -890,10 +914,7 @@ void Shader::createDescriptorSetLayout() layoutBinding.binding = val.location; layoutBinding.descriptorType = type; layoutBinding.descriptorCount = val.count; - if (isCompute) - layoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - else - layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + layoutBinding.stageFlags = stageFlags; bindings.push_back(layoutBinding); } @@ -905,10 +926,7 @@ void Shader::createDescriptorSetLayout() uniformBinding.binding = uniformLocation; uniformBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; uniformBinding.descriptorCount = 1; - if (isCompute) - uniformBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - else - uniformBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + uniformBinding.stageFlags = stageFlags; bindings.push_back(uniformBinding); } diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 757ad1f42..b7de91b16 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -61,7 +61,7 @@ public: void updateUniform(const UniformInfo *info, int count) override; void sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) override; - void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override {} + void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override; bool hasUniform(const std::string &name) const override; @@ -81,6 +81,8 @@ private: const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename); + void initDescriptorSet(); + void updateUniform(const UniformInfo* info, int count, bool internal); VkDescriptorSet allocateDescriptorSet();