Browse Source

Vulkan pipeline layout creation and caching

BearishSun 9 years ago
parent
commit
ce7fad6a81

+ 30 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanDescriptorManager.h

@@ -20,6 +20,21 @@ namespace BansheeEngine
 
 		VulkanDescriptorLayout* layout;
 	};
+
+	/** Used as a key in a hash map containing pipeline layouts. */
+	struct VulkanPipelineLayoutKey
+	{
+		VulkanPipelineLayoutKey(VulkanDescriptorLayout** layouts, UINT32 numLayouts);
+
+		/** Compares two pipeline layouts. */
+		bool operator==(const VulkanPipelineLayoutKey& rhs) const;
+
+		/** Calculates a has value for the provided descriptor layouts. */
+		size_t calculateHash() const;
+
+		UINT32 numLayouts;
+		VulkanDescriptorLayout** layouts;
+	};
 }
 
 /** @cond STDLIB */
@@ -29,7 +44,7 @@ namespace BansheeEngine
 
 namespace std
 {
-	/**	Hash value generator for VulkanDescriptorLayout. */
+	/**	Hash value generator for VulkanLayoutKey. */
 	template<>
 	struct hash<BansheeEngine::VulkanLayoutKey>
 	{
@@ -41,6 +56,16 @@ namespace std
 			return BansheeEngine::VulkanDescriptorLayout::calculateHash(value.bindings, value.numBindings);
 		}
 	};
+
+	/**	Hash value generator for VulkanPipelineLayoutKey. */
+	template<>
+	struct hash<BansheeEngine::VulkanPipelineLayoutKey>
+	{
+		size_t operator()(const BansheeEngine::VulkanPipelineLayoutKey& value) const
+		{
+			return value.calculateHash();
+		}
+	};
 }
 
 /** @} */
@@ -65,10 +90,14 @@ namespace BansheeEngine
 		/** Allocates a new empty descriptor set matching the provided layout. */
 		VulkanDescriptorSet* createSet(VulkanDescriptorLayout* layout);
 
+		/** Attempts to find an existing one, or allocates a new pipeline layout based on the provided descriptor layouts. */
+		VkPipelineLayout getPipelineLayout(VulkanDescriptorLayout** layouts, UINT32 numLayouts);
+
 	protected:
 		VulkanDevice& mDevice;
 
 		UnorderedSet<VulkanLayoutKey> mLayouts; 
+		UnorderedMap<VulkanPipelineLayoutKey, VkPipelineLayout> mPipelineLayouts;
 		Vector<VulkanDescriptorPool*> mPools;
 	};
 

+ 1 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuParams.h

@@ -73,6 +73,7 @@ namespace BansheeEngine
 		{
 			PerSetData* perSetData;
 			UINT32 numSets;
+			VkPipelineLayout pipelineLayout;
 		};
 
 		friend class VulkanHardwareBufferCoreManager;

+ 64 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanDescriptorManager.cpp

@@ -40,6 +40,35 @@ namespace BansheeEngine
 		return true;
 	}
 
+	VulkanPipelineLayoutKey::VulkanPipelineLayoutKey(VulkanDescriptorLayout** layouts, UINT32 numLayouts)
+		:layouts(layouts), numLayouts(numLayouts)
+	{
+		
+	}
+
+	bool VulkanPipelineLayoutKey::operator==(const VulkanPipelineLayoutKey& rhs) const
+	{
+		if (numLayouts != rhs.numLayouts)
+			return false;
+
+		for (UINT32 i = 0; i < numLayouts; i++)
+		{
+			if (layouts[i] != rhs.layouts[i])
+				return false;
+		}
+
+		return true;
+	}
+
+	size_t VulkanPipelineLayoutKey::calculateHash() const
+	{
+		size_t hash = 0;
+		for (UINT32 i = 0; i < numLayouts; i++)
+			hash_combine(hash, layouts[i]->getHash());
+
+		return hash;
+	}
+
 	VulkanDescriptorManager::VulkanDescriptorManager(VulkanDevice& device)
 		:mDevice(device)
 	{
@@ -54,6 +83,9 @@ namespace BansheeEngine
 			bs_free(entry.bindings);
 		}
 
+		for(auto& entry : mPipelineLayouts)
+			vkDestroyPipelineLayout(mDevice.getLogical(), entry.second, gVulkanAllocator);
+
 		for (auto& entry : mPools)
 			bs_delete(entry);
 	}
@@ -104,4 +136,36 @@ namespace BansheeEngine
 
 		return mDevice.getResourceManager().create<VulkanDescriptorSet>(set, allocateInfo.descriptorPool);
 	}
+
+	VkPipelineLayout VulkanDescriptorManager::getPipelineLayout(VulkanDescriptorLayout** layouts, UINT32 numLayouts)
+	{
+		VulkanPipelineLayoutKey key(layouts, numLayouts);
+
+		auto iterFind = mPipelineLayouts.find(key);
+		if (iterFind != mPipelineLayouts.end())
+			return iterFind->second;
+
+		// Create new
+		VkDescriptorSetLayout* setLayouts = (VkDescriptorSetLayout*)bs_stack_alloc(sizeof(VkDescriptorSetLayout) * numLayouts);
+		for(UINT32 i = 0; i < numLayouts; i++)
+			setLayouts[i] = layouts[i]->getHandle();
+
+		VkPipelineLayoutCreateInfo layoutCI;
+		layoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+		layoutCI.pNext = nullptr;
+		layoutCI.flags = 0;
+		layoutCI.pushConstantRangeCount = 0;
+		layoutCI.pPushConstantRanges = nullptr;
+		layoutCI.setLayoutCount = numLayouts;
+		layoutCI.pSetLayouts = setLayouts;
+
+		VkPipelineLayout pipelineLayout;
+		VkResult result = vkCreatePipelineLayout(mDevice.getLogical(), &layoutCI, gVulkanAllocator, &pipelineLayout);
+		assert(result != VK_SUCCESS);
+
+		bs_stack_free(setLayouts);
+
+		mPipelineLayouts.insert(std::make_pair(key, pipelineLayout));
+		return pipelineLayout;
+	}
 }

+ 8 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParams.cpp

@@ -9,6 +9,7 @@
 #include "BsVulkanTexture.h"
 #include "BsVulkanHardwareBuffer.h"
 #include "BsVulkanDescriptorSet.h"
+#include "BsVulkanDescriptorLayout.h"
 #include "BsVulkanSamplerState.h"
 #include "BsVulkanGpuBuffer.h"
 #include "BsVulkanCommandBuffer.h"
@@ -167,6 +168,7 @@ namespace BansheeEngine
 			dataIter += sizeof(perSetBytes);
 
 			VulkanDescriptorManager& descManager = devices[i]->getDescriptorManager();
+			VulkanDescriptorLayout** layouts = (VulkanDescriptorLayout**)bs_stack_alloc(numSets * sizeof(VulkanDescriptorLayout*));
 
 			UINT32 bindingOffset = 0;
 			for (UINT32 j = 0; j < numSets; j++)
@@ -185,6 +187,8 @@ namespace BansheeEngine
 				perSetData.set = descManager.createSet(perSetData.layout);
 				perSetData.numElements = numBindingsPerSet;
 
+				layouts[j] = perSetData.layout;
+
 				for(UINT32 k = 0; k < numBindingsPerSet; k++)
 				{
 					// Note: Instead of using one structure per binding, it's possible to update multiple at once
@@ -238,6 +242,10 @@ namespace BansheeEngine
 
 				bindingOffset += numBindingsPerSet;
 			}
+
+			mPerDeviceData[i].pipelineLayout = descManager.getPipelineLayout(layouts, numSets);
+
+			bs_stack_free(layouts);
 		}
 
 		bs_stack_free(bindingOffsets);