diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 97c6102e74d..c90760e9ba7 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -88,28 +88,6 @@ VmaAllocator createAllocator(VkInstance instance, VkPhysicalDevice physicalDevic return allocator; } -VulkanTexture* createEmptyTexture(VkDevice device, VkPhysicalDevice physicalDevice, - VulkanContext const& context, VmaAllocator allocator, VulkanCommands* commands, - VulkanResourceAllocator* handleAllocator, VulkanStagePool& stagePool) { - VulkanTexture* emptyTexture = new VulkanTexture(device, physicalDevice, context, allocator, - commands, handleAllocator, SamplerType::SAMPLER_2D, 1, TextureFormat::RGBA8, 1, 1, 1, 1, - TextureUsage::DEFAULT | TextureUsage::COLOR_ATTACHMENT | TextureUsage::SUBPASS_INPUT, - stagePool, true /* heap allocated */); - uint32_t black = 0; - PixelBufferDescriptor pbd(&black, 4, PixelDataFormat::RGBA, PixelDataType::UBYTE); - emptyTexture->updateImage(pbd, 1, 1, 1, 0, 0, 0, 0); - return emptyTexture; -} - -VulkanBufferObject* createEmptyBufferObject(VmaAllocator allocator, VulkanStagePool& stagePool, - VulkanCommands* commands) { - VulkanBufferObject* obj = - new VulkanBufferObject(allocator, stagePool, 1, BufferObjectBinding::UNIFORM); - uint8_t byte = 0; - obj->buffer.loadFromCpu(commands->get().buffer(), &byte, 0, 1); - return obj; -} - #if FVK_ENABLED(FVK_DEBUG_VALIDATION) VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, @@ -255,13 +233,6 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex #endif mTimestamps = std::make_unique(mPlatform->getDevice()); - - mEmptyTexture = createEmptyTexture(mPlatform->getDevice(), mPlatform->getPhysicalDevice(), - mContext, mAllocator, &mCommands, &mResourceAllocator, mStagePool); - mEmptyBufferObject = createEmptyBufferObject(mAllocator, mStagePool, &mCommands); - - mDescriptorSetManager.setPlaceHolders(mSamplerCache.getSampler({}), mEmptyTexture, - mEmptyBufferObject); } VulkanDriver::~VulkanDriver() noexcept = default; @@ -326,9 +297,6 @@ void VulkanDriver::terminate() { // to those commands are no longer referenced. finish(0); - delete mEmptyBufferObject; - delete mEmptyTexture; - // Command buffers should come first since it might have commands depending on resources that // are about to be destroyed. mCommands.terminate(); diff --git a/filament/backend/src/vulkan/VulkanDriver.h b/filament/backend/src/vulkan/VulkanDriver.h index d811bfebb2a..a3a9456a82b 100644 --- a/filament/backend/src/vulkan/VulkanDriver.h +++ b/filament/backend/src/vulkan/VulkanDriver.h @@ -115,10 +115,6 @@ class VulkanDriver final : public DriverBase { VulkanPlatform* mPlatform = nullptr; std::unique_ptr mTimestamps; - // Placeholder resources - VulkanTexture* mEmptyTexture; - VulkanBufferObject* mEmptyBufferObject; - VulkanSwapChain* mCurrentSwapChain = nullptr; VulkanRenderTarget* mDefaultRenderTarget = nullptr; VulkanRenderPass mCurrentRenderPass = {}; diff --git a/filament/backend/src/vulkan/VulkanHandles.cpp b/filament/backend/src/vulkan/VulkanHandles.cpp index e2adea0f560..a2f63c4b60f 100644 --- a/filament/backend/src/vulkan/VulkanHandles.cpp +++ b/filament/backend/src/vulkan/VulkanHandles.cpp @@ -115,7 +115,6 @@ VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(DescriptorSetLayout const& void VulkanDescriptorSet::acquire(VulkanTexture* texture) { mResources.acquire(texture); - mTextures[mTextureCount++] = texture; } void VulkanDescriptorSet::acquire(VulkanBufferObject* bufferObject) { diff --git a/filament/backend/src/vulkan/VulkanHandles.h b/filament/backend/src/vulkan/VulkanHandles.h index 16f9c888f2e..1c8fe9d786c 100644 --- a/filament/backend/src/vulkan/VulkanHandles.h +++ b/filament/backend/src/vulkan/VulkanHandles.h @@ -151,17 +151,9 @@ struct VulkanDescriptorSet : public VulkanResource, HwDescriptorSet { void acquire(VulkanBufferObject* texture); - bool hasTexture(VulkanTexture* texture) { - return std::any_of(mTextures.begin(), mTextures.end(), - [texture](auto t) { return t == texture; }); - } - - // TODO: maybe change to fixed size for performance. VkDescriptorSet const vkSet; private: - std::array mTextures = { nullptr }; - uint8_t mTextureCount = 0; VulkanAcquireOnlyResourceManager mResources; OnRecycle mOnRecycleFn; }; @@ -202,10 +194,6 @@ struct VulkanProgram : public HwProgram, VulkanResource { inline VkShaderModule getFragmentShader() const { return mInfo->shaders[1]; } - inline utils::FixedCapacityVector const& getBindingToSamplerIndex() const { - return mInfo->bindingToSamplerIndex; - } - // Get a list of the sampler binding indices so that we don't have to loop through all possible // samplers. inline BindingList const& getBindings() const { return mInfo->bindings; } @@ -236,8 +224,7 @@ struct VulkanProgram : public HwProgram, VulkanResource { private: struct PipelineInfo { explicit PipelineInfo(backend::Program const& program) noexcept - : bindingToSamplerIndex(MAX_SAMPLER_COUNT, 0xffff), - pushConstantDescription(program) + : pushConstantDescription(program) #if FVK_ENABLED_DEBUG_SAMPLER_NAME , bindingToName(MAX_SAMPLER_COUNT, "") #endif @@ -245,8 +232,6 @@ struct VulkanProgram : public HwProgram, VulkanResource { BindingList bindings; - // We store the samplerGroupIndex as the top 8-bit and the index within each group as the lower 8-bit. - utils::FixedCapacityVector bindingToSamplerIndex; VkShaderModule shaders[MAX_SHADER_MODULES] = { VK_NULL_HANDLE }; PushConstantDescription pushConstantDescription; diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp index eb72d1be908..660001083e8 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp +++ b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp @@ -193,64 +193,6 @@ class DescriptorPool { UnusedSetMap mUnused; }; -// This is an ever-expanding pool of sets where it -// 1. Keeps a list of smaller pools of different layout-dimensions. -// 2. Will add a pool if existing pool are not compatible with the requested layout o runs out. -class DescriptorInfinitePool { -private: - static constexpr uint16_t EXPECTED_SET_COUNT = 10; - static constexpr float SET_COUNT_GROWTH_FACTOR = 1.5; - -public: - DescriptorInfinitePool(VkDevice device) - : mDevice(device) {} - - VkDescriptorSet obtainSet(VulkanDescriptorSetLayout* layout) { - auto const vklayout = layout->getVkLayout(); - DescriptorPool* sameTypePool = nullptr; - for (auto& pool: mPools) { - if (!pool->canAllocate(layout->count)) { - continue; - } - if (auto set = pool->obtainSet(vklayout); set != VK_NULL_HANDLE) { - return set; - } - if (!sameTypePool || sameTypePool->capacity() < pool->capacity()) { - sameTypePool = pool.get(); - } - } - - uint16_t capacity = EXPECTED_SET_COUNT; - if (sameTypePool) { - // Exponentially increase the size of the pool to ensure we don't hit this too often. - capacity = std::ceil(sameTypePool->capacity() * SET_COUNT_GROWTH_FACTOR); - } - - // We need to increase the set of pools by one. - mPools.push_back(std::make_unique(mDevice, - DescriptorCount::fromLayoutBitmask(layout->bitmask), capacity)); - auto& pool = mPools.back(); - auto ret = pool->obtainSet(vklayout); - assert_invariant(ret != VK_NULL_HANDLE && "failed to obtain a set?"); - return ret; - } - - void recycle(DescriptorCount const& count, VkDescriptorSetLayout vklayout, - VkDescriptorSet vkSet) { - for (auto& pool: mPools) { - if (!pool->canAllocate(count)) { - continue; - } - pool->recycle(vklayout, vkSet); - break; - } - } - -private: - VkDevice mDevice; - std::vector> mPools; -}; - template struct Equal { bool operator()(Key const& k1, Key const& k2) const { @@ -318,7 +260,67 @@ inline VkDescriptorSetLayout createLayout(VkDevice device, BitmaskGroup const& b return layout; } -class DescriptorSetLayoutManager { +} // anonymous namespace + +// This is an ever-expanding pool of sets where it +// 1. Keeps a list of smaller pools of different layout-dimensions. +// 2. Will add a pool if existing pool are not compatible with the requested layout o runs out. +class VulkanDescriptorSetManager::DescriptorInfinitePool { +private: + static constexpr uint16_t EXPECTED_SET_COUNT = 10; + static constexpr float SET_COUNT_GROWTH_FACTOR = 1.5; + +public: + DescriptorInfinitePool(VkDevice device) + : mDevice(device) {} + + VkDescriptorSet obtainSet(VulkanDescriptorSetLayout* layout) { + auto const vklayout = layout->getVkLayout(); + DescriptorPool* sameTypePool = nullptr; + for (auto& pool: mPools) { + if (!pool->canAllocate(layout->count)) { + continue; + } + if (auto set = pool->obtainSet(vklayout); set != VK_NULL_HANDLE) { + return set; + } + if (!sameTypePool || sameTypePool->capacity() < pool->capacity()) { + sameTypePool = pool.get(); + } + } + + uint16_t capacity = EXPECTED_SET_COUNT; + if (sameTypePool) { + // Exponentially increase the size of the pool to ensure we don't hit this too often. + capacity = std::ceil(sameTypePool->capacity() * SET_COUNT_GROWTH_FACTOR); + } + + // We need to increase the set of pools by one. + mPools.push_back(std::make_unique(mDevice, + DescriptorCount::fromLayoutBitmask(layout->bitmask), capacity)); + auto& pool = mPools.back(); + auto ret = pool->obtainSet(vklayout); + assert_invariant(ret != VK_NULL_HANDLE && "failed to obtain a set?"); + return ret; + } + + void recycle(DescriptorCount const& count, VkDescriptorSetLayout vklayout, + VkDescriptorSet vkSet) { + for (auto& pool: mPools) { + if (!pool->canAllocate(count)) { + continue; + } + pool->recycle(vklayout, vkSet); + break; + } + } + +private: + VkDevice mDevice; + std::vector> mPools; +}; + +class VulkanDescriptorSetManager::DescriptorSetLayoutManager { public: DescriptorSetLayoutManager(VkDevice device) : mDevice(device) {} @@ -345,329 +347,226 @@ class DescriptorSetLayoutManager { mVkLayouts; }; -} // anonymous namespace - -class VulkanDescriptorSetManager::Impl { +class VulkanDescriptorSetManager::DescriptorSetHistory { private: - struct DescriptorSetHistory { - private: - using TextureBundle = std::pair; - public: - DescriptorSetHistory() - : dynamicUboCount(0), - mResources(nullptr) {} - - DescriptorSetHistory(UniformBufferBitmask const& dynamicUbo, uint8_t uniqueDynamicUboCount, - VulkanResourceAllocator* allocator, VulkanDescriptorSet* set) - : dynamicUboMask(dynamicUbo), - dynamicUboCount(uniqueDynamicUboCount), - mResources(allocator), - mSet(set), - mBound(false) { - assert_invariant(set); - // initial state is unbound. - mResources.acquire(mSet); - unbind(); - } - - ~DescriptorSetHistory() { - if (mSet) { - mResources.clear(); - } - } - - void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept { - mOffsets = std::move(offsets); - mBound = false; - } - - void write(uint8_t binding) noexcept { - mBound = false; - } - - // Ownership will be transfered to the commandbuffer. - void bind(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout, uint8_t index) noexcept { - VkCommandBuffer const cmdbuffer = commands->buffer(); - vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, - index, 1, &mSet->vkSet, dynamicUboCount, mOffsets.data()); - - commands->acquire(mSet); - mResources.clear(); - mBound = true; - } - - void unbind() noexcept { - mResources.acquire(mSet); - mBound = false; - } - - bool bound() const noexcept { return mBound; } - - UniformBufferBitmask const dynamicUboMask; - uint8_t const dynamicUboCount; - - private: - FixedSizeVulkanResourceManager<1> mResources; - VulkanDescriptorSet* mSet = nullptr; - - backend::DescriptorSetOffsetArray mOffsets; - bool mBound = false; - }; - - using DescriptorSetHistoryArray = - std::array; - - struct BoundInfo { - VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; - DescriptorSetMask setMask; - DescriptorSetHistoryArray boundSets; - - bool operator==(BoundInfo const& info) const { - if (pipelineLayout != info.pipelineLayout || setMask != info.setMask) { - return false; - } - bool equal = true; - setMask.forEachSetBit([&](size_t i) { - if (boundSets[i] != info.boundSets[i]) { - equal = false; - } - }); - return equal; - } - }; + using TextureBundle = std::pair; public: - Impl(VkDevice device, VulkanResourceAllocator* resourceAllocator) - : mDevice(device), - mResourceAllocator(resourceAllocator), - mLayoutManager(device), - mDescriptorPool(device) {} - - // bind() is not really binding the set but just stashing until we have all the info - // (pipelinelayout). - void bind(uint8_t setIndex, VulkanDescriptorSet* set, - backend::DescriptorSetOffsetArray&& offsets) { - auto& history = mHistory[set]; - history.setOffsets(std::move(offsets)); - - auto lastHistory = mStashedSets[setIndex]; - if (lastHistory) { - lastHistory->unbind(); - } - mStashedSets[setIndex] = &history; + DescriptorSetHistory() + : dynamicUboCount(0), + mResources(nullptr) {} + + DescriptorSetHistory(UniformBufferBitmask const& dynamicUbo, uint8_t uniqueDynamicUboCount, + VulkanResourceAllocator* allocator, VulkanDescriptorSet* set) + : dynamicUboMask(dynamicUbo), + dynamicUboCount(uniqueDynamicUboCount), + mResources(allocator), + mSet(set), + mBound(false) { + assert_invariant(set); + // initial state is unbound. + unbind(); } - void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout, - DescriptorSetMask const& setMask) { - DescriptorSetHistoryArray& updateSets = mStashedSets; - - // setMask indicates the set of descriptor sets the driver wants to bind, curMask is the - // actual set of sets that *needs* to be bound. - DescriptorSetMask curMask = setMask; - - setMask.forEachSetBit([&](size_t index) { - if (!updateSets[index] || updateSets[index]->bound()) { - curMask.unset(index); - } - }); - - BoundInfo nextInfo = { - pipelineLayout, - setMask, - updateSets, - }; - if (curMask.none() && mLastBoundInfo == nextInfo) { - return; + ~DescriptorSetHistory() { + if (mSet) { + mResources.clear(); } + } - curMask.forEachSetBit([&updateSets, commands, pipelineLayout](size_t index) { - updateSets[index]->bind(commands, pipelineLayout, index); - }); - mLastBoundInfo = nextInfo; + void setOffsets(backend::DescriptorSetOffsetArray&& offsets) noexcept { + mOffsets = std::move(offsets); + mBound = false; } - void updateBuffer(VulkanDescriptorSet* set, uint8_t binding, VulkanBufferObject* bufferObject, - VkDeviceSize offset, VkDeviceSize size) noexcept { - VkDescriptorBufferInfo const info = { - .buffer = bufferObject->buffer.getGpuBuffer(), - .offset = offset, - .range = size, - }; + void write(uint8_t binding) noexcept { mBound = false; } - VkDescriptorType type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - auto& history = mHistory[set]; + // Ownership will be transfered to the commandbuffer. + void bind(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout, + uint8_t index) noexcept { + VkCommandBuffer const cmdbuffer = commands->buffer(); + vkCmdBindDescriptorSets(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, index, + 1, &mSet->vkSet, dynamicUboCount, mOffsets.data()); - if (history.dynamicUboMask.test(binding)) { - type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - } - VkWriteDescriptorSet const descriptorWrite = { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .pNext = nullptr, - .dstSet = set->vkSet, - .dstBinding = binding, - .descriptorCount = 1, - .descriptorType = type, - .pBufferInfo = &info, - }; - vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr); - set->acquire(bufferObject); - history.write(binding); + commands->acquire(mSet); + mResources.clear(); + mBound = true; } - void updateSampler(VulkanDescriptorSet* set, uint8_t binding, VulkanTexture* texture, - VkSampler sampler) noexcept { - VkDescriptorImageInfo info{ - .sampler = sampler, - }; - VkImageSubresourceRange const range = texture->getPrimaryViewRange(); - VkImageViewType const expectedType = texture->getViewType(); - if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT) && - expectedType == VK_IMAGE_VIEW_TYPE_2D) { - // If the sampler is part of a mipmapped depth texture, where one of the level *can* be - // an attachment, then the sampler for this texture has the same view properties as a - // view for an attachment. Therefore, we can use getAttachmentView to get a - // corresponding VkImageView. - info.imageView = texture->getAttachmentView(range); - } else { - info.imageView = texture->getViewForType(range, expectedType); - } - info.imageLayout = imgutil::getVkLayout(texture->getPrimaryImageLayout()); - VkWriteDescriptorSet const descriptorWrite = { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .pNext = nullptr, - .dstSet = set->vkSet, - .dstBinding = binding, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .pImageInfo = &info, - }; - vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr); - set->acquire(texture); - mHistory[set].write(binding); + void unbind() noexcept { + mResources.acquire(mSet); + mBound = false; } - void updateInputAttachment(VulkanDescriptorSet* set, VulkanAttachment attachment) noexcept { - // TOOD: fill-in this region - } + bool bound() const noexcept { return mBound; } - void setPlaceHolders(VkSampler sampler, VulkanTexture* texture, - VulkanBufferObject* bufferObject) noexcept { - mPlaceHolderBufferInfo = { - .buffer = bufferObject->buffer.getGpuBuffer(), - .offset = 0, - .range = 1, - }; - mPlaceHolderImageInfo = { - .sampler = sampler, - .imageView = texture->getPrimaryImageView(), - .imageLayout = imgutil::getVkLayout(texture->getPrimaryImageLayout()), - }; - } + UniformBufferBitmask const dynamicUboMask; + uint8_t const dynamicUboCount; - void createSet(Handle handle, VulkanDescriptorSetLayout* layout) { - auto const vkSet = mDescriptorPool.obtainSet(layout); - auto const& count = layout->count; - auto const vklayout = layout->getVkLayout(); - VulkanDescriptorSet* set = - mResourceAllocator->construct(handle, mResourceAllocator, - vkSet, [vkSet, count, vklayout, this](VulkanDescriptorSet* set) { - eraseSetFromHistory(set); - mDescriptorPool.recycle(count, vklayout, vkSet); - }); - mHistory.emplace( - std::piecewise_construct, - std::forward_as_tuple(set), - std::forward_as_tuple(layout->bitmask.dynamicUbo, layout->count.dynamicUbo, - mResourceAllocator, set)); - } +private: + FixedSizeVulkanResourceManager<1> mResources; + VulkanDescriptorSet* mSet = nullptr; - void destroySet(Handle handle) { - VulkanDescriptorSet* set = mResourceAllocator->handle_cast(handle); - eraseSetFromHistory(set); - } + backend::DescriptorSetOffsetArray mOffsets; + bool mBound = false; +}; - void initVkLayout(VulkanDescriptorSetLayout* layout) { - layout->setVkLayout(mLayoutManager.getVkLayout(layout)); - } +VulkanDescriptorSetManager::VulkanDescriptorSetManager(VkDevice device, + VulkanResourceAllocator* resourceAllocator) + : mDevice(device), + mResourceAllocator(resourceAllocator), + mLayoutManager(std::make_unique(device)), + mDescriptorPool(std::make_unique(device)) {} -private: - inline void eraseSetFromHistory(VulkanDescriptorSet* set) { - DescriptorSetHistory* history = &mHistory[set]; - mHistory.erase(set); +VulkanDescriptorSetManager::~VulkanDescriptorSetManager() = default; - for (uint8_t i = 0; i < mStashedSets.size(); ++i) { - if (mStashedSets[i] == history) { - mStashedSets[i] = nullptr; - } - } +void VulkanDescriptorSetManager::terminate() noexcept{ + mLayoutManager.reset(); + mDescriptorPool.reset(); + mHistory.clear(); +} + +// bind() is not really binding the set but just stashing until we have all the info +// (pipelinelayout). +void VulkanDescriptorSetManager::bind(uint8_t setIndex, VulkanDescriptorSet* set, + backend::DescriptorSetOffsetArray&& offsets) { + auto history = mHistory[set].get(); + history->setOffsets(std::move(offsets)); + + auto lastHistory = mStashedSets[setIndex]; + if (lastHistory) { + lastHistory->unbind(); } + mStashedSets[setIndex] = history; +} - VkDevice mDevice; - VulkanResourceAllocator* mResourceAllocator; - DescriptorSetLayoutManager mLayoutManager; - DescriptorInfinitePool mDescriptorPool; - std::pair mInputAttachment; - std::unordered_map mHistory; - DescriptorSetHistoryArray mStashedSets = {}; +void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands, + VkPipelineLayout pipelineLayout, DescriptorSetMask const& setMask) { + DescriptorSetHistoryArray& updateSets = mStashedSets; - BoundInfo mLastBoundInfo; + // setMask indicates the set of descriptor sets the driver wants to bind, curMask is the + // actual set of sets that *needs* to be bound. + DescriptorSetMask curMask = setMask; - VkDescriptorBufferInfo mPlaceHolderBufferInfo; - VkDescriptorImageInfo mPlaceHolderImageInfo; -}; + setMask.forEachSetBit([&](size_t index) { + if (!updateSets[index] || updateSets[index]->bound()) { + curMask.unset(index); + } + }); -VulkanDescriptorSetManager::VulkanDescriptorSetManager(VkDevice device, - VulkanResourceAllocator* resourceAllocator) - : mImpl(new Impl(device, resourceAllocator)) {} + BoundInfo nextInfo = { + pipelineLayout, + setMask, + updateSets, + }; + if (curMask.none() && mLastBoundInfo == nextInfo) { + return; + } -void VulkanDescriptorSetManager::terminate() noexcept { - assert_invariant(mImpl); - delete mImpl; - mImpl = nullptr; + curMask.forEachSetBit([&updateSets, commands, pipelineLayout](size_t index) { + updateSets[index]->bind(commands, pipelineLayout, index); + }); + mLastBoundInfo = nextInfo; } void VulkanDescriptorSetManager::updateBuffer(VulkanDescriptorSet* set, uint8_t binding, VulkanBufferObject* bufferObject, VkDeviceSize offset, VkDeviceSize size) noexcept { - mImpl->updateBuffer(set, binding, bufferObject, offset, size); + VkDescriptorBufferInfo const info = { + .buffer = bufferObject->buffer.getGpuBuffer(), + .offset = offset, + .range = size, + }; + + VkDescriptorType type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + auto& history = mHistory[set]; + + if (history->dynamicUboMask.test(binding)) { + type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + } + VkWriteDescriptorSet const descriptorWrite = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = set->vkSet, + .dstBinding = binding, + .descriptorCount = 1, + .descriptorType = type, + .pBufferInfo = &info, + }; + vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr); + set->acquire(bufferObject); + history->write(binding); } void VulkanDescriptorSetManager::updateSampler(VulkanDescriptorSet* set, uint8_t binding, VulkanTexture* texture, VkSampler sampler) noexcept { - mImpl->updateSampler(set, binding, texture, sampler); + VkDescriptorImageInfo info{ + .sampler = sampler, + }; + VkImageSubresourceRange const range = texture->getPrimaryViewRange(); + VkImageViewType const expectedType = texture->getViewType(); + if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT) && + expectedType == VK_IMAGE_VIEW_TYPE_2D) { + // If the sampler is part of a mipmapped depth texture, where one of the level *can* be + // an attachment, then the sampler for this texture has the same view properties as a + // view for an attachment. Therefore, we can use getAttachmentView to get a + // corresponding VkImageView. + info.imageView = texture->getAttachmentView(range); + } else { + info.imageView = texture->getViewForType(range, expectedType); + } + info.imageLayout = imgutil::getVkLayout(texture->getPrimaryImageLayout()); + VkWriteDescriptorSet const descriptorWrite = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = set->vkSet, + .dstBinding = binding, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &info, + }; + vkUpdateDescriptorSets(mDevice, 1, &descriptorWrite, 0, nullptr); + set->acquire(texture); + mHistory[set]->write(binding); } void VulkanDescriptorSetManager::updateInputAttachment(VulkanDescriptorSet* set, VulkanAttachment attachment) noexcept { - mImpl->updateInputAttachment(set, attachment); -} - -void VulkanDescriptorSetManager::setPlaceHolders(VkSampler sampler, VulkanTexture* texture, - VulkanBufferObject* bufferObject) noexcept { - mImpl->setPlaceHolders(sampler, texture, bufferObject); -} - -void VulkanDescriptorSetManager::bind(uint8_t setIndex, VulkanDescriptorSet* set, - backend::DescriptorSetOffsetArray&& offsets) { - return mImpl->bind(setIndex, set, std::move(offsets)); -} - -void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands, - VkPipelineLayout pipelineLayout, DescriptorSetMask const& setMask) { - mImpl->commit(commands, pipelineLayout, setMask); + // TOOD: fill-in this region } void VulkanDescriptorSetManager::createSet(Handle handle, VulkanDescriptorSetLayout* layout) { - mImpl->createSet(handle, layout); + auto const vkSet = mDescriptorPool->obtainSet(layout); + auto const& count = layout->count; + auto const vklayout = layout->getVkLayout(); + VulkanDescriptorSet* set = mResourceAllocator->construct(handle, + mResourceAllocator, vkSet, [vkSet, count, vklayout, this](VulkanDescriptorSet* set) { + eraseSetFromHistory(set); + mDescriptorPool->recycle(count, vklayout, vkSet); + }); + mHistory[set] = std::make_unique(layout->bitmask.dynamicUbo, + layout->count.dynamicUbo, mResourceAllocator, set); } void VulkanDescriptorSetManager::destroySet(Handle handle) { - mImpl->destroySet(handle); + VulkanDescriptorSet* set = mResourceAllocator->handle_cast(handle); + eraseSetFromHistory(set); } void VulkanDescriptorSetManager::initVkLayout(VulkanDescriptorSetLayout* layout) { - mImpl->initVkLayout(layout); + layout->setVkLayout(mLayoutManager->getVkLayout(layout)); +} + +void VulkanDescriptorSetManager::eraseSetFromHistory(VulkanDescriptorSet* set) { + DescriptorSetHistory* history = mHistory[set].get(); + mHistory.erase(set); + + for (uint8_t i = 0; i < mStashedSets.size(); ++i) { + if (mStashedSets[i] == history) { + mStashedSets[i] = nullptr; + } + } } -}// namespace filament::backend +} // namespace filament::backend diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h index 6d78f31b244..a98cc84b454 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h +++ b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h @@ -30,6 +30,8 @@ #include #include +#include + namespace filament::backend { // [GDSR]: Great-Descriptor-Set-Refactor: As of 03/20/24, the Filament frontend is planning to @@ -45,6 +47,7 @@ class VulkanDescriptorSetManager { using DescriptorSetLayoutArray = VulkanDescriptorSetLayout::DescriptorSetLayoutArray; VulkanDescriptorSetManager(VkDevice device, VulkanResourceAllocator* resourceAllocator); + ~VulkanDescriptorSetManager(); void terminate() noexcept; @@ -71,8 +74,43 @@ class VulkanDescriptorSetManager { void initVkLayout(VulkanDescriptorSetLayout* layout); private: - class Impl; - Impl* mImpl; + class DescriptorSetHistory; + class DescriptorSetLayoutManager; + class DescriptorInfinitePool; + + void eraseSetFromHistory(VulkanDescriptorSet* set); + + using DescriptorSetHistoryArray = + std::array; + + struct BoundInfo { + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + DescriptorSetMask setMask; + DescriptorSetHistoryArray boundSets; + + bool operator==(BoundInfo const& info) const { + if (pipelineLayout != info.pipelineLayout || setMask != info.setMask) { + return false; + } + bool equal = true; + setMask.forEachSetBit([&](size_t i) { + if (boundSets[i] != info.boundSets[i]) { + equal = false; + } + }); + return equal; + } + }; + + VkDevice mDevice; + VulkanResourceAllocator* mResourceAllocator; + std::unique_ptr mLayoutManager; + std::unique_ptr mDescriptorPool; + std::pair mInputAttachment; + std::unordered_map> mHistory; + DescriptorSetHistoryArray mStashedSets = {}; + + BoundInfo mLastBoundInfo; }; }// namespace filament::backend