Parcourir la source

Vulkan: Added support for shared storage buffer objects

BearishSun il y a 9 ans
Parent
commit
6732f7076a

+ 9 - 7
Source/BansheeVulkanRenderAPI/Include/BsVulkanHardwareBuffer.h

@@ -94,15 +94,17 @@ namespace bs { namespace ct
 		enum BufferType
 		{
 			/** Contains geometry vertices and their properties. */
-			BT_VERTEX = 0x1,
+			BT_VERTEX,
 			/** Contains triangle to vertex mapping. */
-			BT_INDEX = 0x2,
+			BT_INDEX,
 			/** Contains GPU program parameters. */
-			BT_UNIFORM = 0x4,
-			/** Generic read-only GPU buffer containing formatted data. */
-			BT_GENERIC = 0x8,
-			/** Generic read/write GPU buffer containing formatted data. */
-			BT_STORAGE = 0x10,
+			BT_UNIFORM,
+			/** Generic read-only GPU buffer containing non-formatted data. */
+			BT_GENERIC,
+			/** Generic read/write GPU buffer containing non-formatted data. */
+			BT_STORAGE,
+			/** Read/write GPU buffer containing structured data. */
+			BT_STRUCTURED
 		};
 
 		VulkanHardwareBuffer(BufferType type, GpuBufferFormat format, GpuBufferUsage usage, UINT32 size,

+ 4 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanHardwareBufferManager.h

@@ -27,6 +27,9 @@ namespace bs { namespace ct
 		/** Returns a buffer that can be used for uniform storage when no other buffer is bound. */
 		VkBuffer getDummyUniformBuffer(UINT32 deviceIdx) const;
 
+		/** Returns a buffer that can be used for structured storage when no other buffer is bound. */
+		VkBuffer getDummyStructuredBuffer(UINT32 deviceIdx) const;
+
 	protected:     
 		/** @copydoc HardwareBufferManager::createVertexBufferInternal */
 		SPtr<VertexBuffer> createVertexBufferInternal(const VERTEX_BUFFER_DESC& desc, 
@@ -51,6 +54,7 @@ namespace bs { namespace ct
 		VulkanHardwareBuffer* mDummyReadBuffer;
 		VulkanHardwareBuffer* mDummyStorageBuffer;
 		VulkanHardwareBuffer* mDummyUniformBuffer;
+		VulkanHardwareBuffer* mDummyStructuredBuffer;
 	};
 
 	/** @} */

+ 4 - 1
Source/BansheeVulkanRenderAPI/Source/BsVulkanDescriptorPool.cpp

@@ -8,7 +8,7 @@ namespace bs { namespace ct
 	VulkanDescriptorPool::VulkanDescriptorPool(VulkanDevice& device)
 		:mDevice(device)
 	{
-		VkDescriptorPoolSize poolSizes[5];
+		VkDescriptorPoolSize poolSizes[6];
 		poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
 		poolSizes[0].descriptorCount = sMaxSampledImages;
 
@@ -24,6 +24,9 @@ namespace bs { namespace ct
 		poolSizes[4].type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
 		poolSizes[4].descriptorCount = sMaxBuffers;
 
+		poolSizes[5].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+		poolSizes[5].descriptorCount = sMaxBuffers;
+
 		VkDescriptorPoolCreateInfo poolCI;
 		poolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
 		poolCI.pNext = nullptr;

+ 45 - 17
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParams.cpp

@@ -177,15 +177,20 @@ namespace bs { namespace ct
 					}
 					else
 					{
-						bool isUniform = writeSetInfo.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+						bool useView = writeSetInfo.descriptorType != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER && 
+							writeSetInfo.descriptorType != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
 
-						if (isUniform)
+						if (!useView)
 						{
 							VkDescriptorBufferInfo& bufferInfo = perSetData.writeInfos[k].buffer;
-							bufferInfo.buffer = vkBufManager.getDummyUniformBuffer(i);
 							bufferInfo.offset = 0;
 							bufferInfo.range = VK_WHOLE_SIZE;
 
+							if(writeSetInfo.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
+								bufferInfo.buffer = vkBufManager.getDummyUniformBuffer(i);
+							else
+								bufferInfo.buffer = vkBufManager.getDummyStructuredBuffer(i);
+
 							writeSetInfo.pBufferInfo = &bufferInfo;
 							writeSetInfo.pTexelBufferView = nullptr;
 						}
@@ -200,6 +205,7 @@ namespace bs { namespace ct
 							else
 								bufferView = vkBufManager.getDummyReadBufferView(i);
 
+							writeSetInfo.pBufferInfo = nullptr;
 							writeSetInfo.pTexelBufferView = &bufferView;
 						}
 
@@ -393,27 +399,49 @@ namespace bs { namespace ct
 			PerSetData& perSetData = mPerDeviceData[i].perSetData[set];
 			VkWriteDescriptorSet& writeSetInfo = perSetData.writeSetInfos[bindingIdx];
 
-			VkBufferView bufferView;
-			if (bufferRes != nullptr)
+			bool useView = writeSetInfo.descriptorType != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+			if (useView)
 			{
-				bufferView = bufferRes->getView();
-				mPerDeviceData[i].buffers[sequentialIdx] = bufferRes->getHandle();
+				VkBufferView bufferView;
+				if (bufferRes != nullptr)
+				{
+					bufferView = bufferRes->getView();
+					mPerDeviceData[i].buffers[sequentialIdx] = bufferRes->getHandle();
+				}
+				else
+				{
+					VulkanHardwareBufferManager& vkBufManager = static_cast<VulkanHardwareBufferManager&>(
+						HardwareBufferManager::instance());
+
+					bool isLoadStore = writeSetInfo.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+					if (isLoadStore)
+						bufferView = vkBufManager.getDummyStorageBufferView(i);
+					else
+						bufferView = vkBufManager.getDummyReadBufferView(i);
+
+					mPerDeviceData[i].buffers[sequentialIdx] = 0;
+				}
+
+				writeSetInfo.pTexelBufferView = &bufferView;
 			}
-			else
+			else // Structured storage buffer
 			{
-				VulkanHardwareBufferManager& vkBufManager = static_cast<VulkanHardwareBufferManager&>(
-					HardwareBufferManager::instance());
+				if (bufferRes != nullptr)
+				{
+					VkBuffer vkBuffer = bufferRes->getHandle();
 
-				bool isLoadStore = writeSetInfo.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
-				if(isLoadStore)
-					bufferView = vkBufManager.getDummyStorageBufferView(i);
+					perSetData.writeInfos[bindingIdx].buffer.buffer = vkBuffer;
+					mPerDeviceData[i].uniformBuffers[sequentialIdx] = vkBuffer;
+				}
 				else
-					bufferView = vkBufManager.getDummyReadBufferView(i);
+				{
+					VulkanHardwareBufferManager& vkBufManager = static_cast<VulkanHardwareBufferManager&>(
+						HardwareBufferManager::instance());
 
-				mPerDeviceData[i].buffers[sequentialIdx] = 0;
+					perSetData.writeInfos[bindingIdx].buffer.buffer = vkBufManager.getDummyStructuredBuffer(i);
+					mPerDeviceData[i].buffers[sequentialIdx] = nullptr;
+				}
 			}
-
-			writeSetInfo.pTexelBufferView = &bufferView;
 		}
 
 		mSetsDirty[set] = true;

+ 15 - 5
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuPipelineParamInfo.cpp

@@ -133,9 +133,6 @@ namespace bs { namespace ct
 			// Set up buffer bindings
 			for (auto& entry : paramDesc->buffers)
 			{
-				bool isLoadStore = entry.second.type != GPOT_BYTE_BUFFER &&
-					entry.second.type != GPOT_STRUCTURED_BUFFER;
-
 				UINT32 bindingIdx = getBindingIdx(entry.second.set, entry.second.slot);
 				assert(bindingIdx != -1);
 
@@ -143,8 +140,21 @@ namespace bs { namespace ct
 				VkDescriptorSetLayoutBinding& binding = layoutInfo.bindings[bindingIdx];
 				binding.descriptorCount = 1;
 				binding.stageFlags |= stageFlagsLookup[i];
-				binding.descriptorType = 
-					isLoadStore ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+
+				switch(entry.second.type)
+				{
+				default:
+				case GPOT_BYTE_BUFFER:
+					binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+					break;
+				case GPOT_RWBYTE_BUFFER:
+					binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+					break;
+				case GPOT_STRUCTURED_BUFFER:
+				case GPOT_RWSTRUCTURED_BUFFER:
+					binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+					break;
+				}
 			}
 		}
 

+ 42 - 20
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuProgram.cpp

@@ -367,8 +367,10 @@ namespace bs { namespace ct
 		for (int i = 0; i < numBlocks; i++)
 		{
 			const glslang::TType* ttype = program->getUniformBlockTType(i);
+			const glslang::TQualifier& qualifier = ttype->getQualifier();
+			const char* name = program->getUniformBlockName(i);
 
-			if (!ttype->getQualifier().hasBinding())
+			if (!qualifier.hasBinding())
 			{
 				log = "Uniform parsing error: Found a uniform block without a binding qualifier. Each uniform block must "
 					" have an explicitly defined binding number.";
@@ -376,21 +378,36 @@ namespace bs { namespace ct
 				return false;
 			}
 
-			const char* name = program->getUniformBlockName(i);
-			int size = program->getUniformBlockSize(i); 
+			if(qualifier.storage == glslang::EvqBuffer) // Shared storage buffer
+			{
+				GpuParamObjectDesc param;
+				param.name = name;
+				param.slot = qualifier.layoutBinding;
+				param.set = qualifier.layoutSet;
+
+				if (param.set == glslang::TQualifier::layoutSetEnd)
+					param.set = 0;
 
-			GpuParamBlockDesc param;
-			param.name = name;
-			param.blockSize = size / 4;
-			param.isShareable = true;
-			param.slot = ttype->getQualifier().layoutBinding;
-			param.set = ttype->getQualifier().layoutSet;
+				param.type = GPOT_RWSTRUCTURED_BUFFER;
+				desc.buffers[name] = param;
+			}
+			else // Uniform buffer
+			{
+				int size = program->getUniformBlockSize(i);
+
+				GpuParamBlockDesc param;
+				param.name = name;
+				param.blockSize = size / 4;
+				param.isShareable = true;
+				param.slot = qualifier.layoutBinding;
+				param.set = qualifier.layoutSet;
 
-			if (param.set == glslang::TQualifier::layoutSetEnd)
-				param.set = 0;
+				if (param.set == glslang::TQualifier::layoutSetEnd)
+					param.set = 0;
 
-			desc.paramBlocks[name] = param;
-			uniformBlockMap[i] = name;
+				desc.paramBlocks[name] = param;
+				uniformBlockMap[i] = name;
+			}
 		}
 
 		// Parse individual uniforms
@@ -398,6 +415,7 @@ namespace bs { namespace ct
 		for (int i = 0; i < numUniforms; i++)
 		{
 			const glslang::TType* ttype = program->getUniformTType(i);
+			const glslang::TQualifier& qualifier = ttype->getQualifier();
 			const char* name = program->getUniformName(i);
 
 			if (ttype->getBasicType() == glslang::EbtSampler) // Object type
@@ -405,7 +423,7 @@ namespace bs { namespace ct
 				// Note: Even though the type is named EbtSampler, all object types are categorized under it (including non
 				// sampled images and buffers)
 
-				if (!ttype->getQualifier().hasBinding())
+				if (!qualifier.hasBinding())
 				{
 					log = "Uniform parsing error: Found an uniform without a binding qualifier. Each uniform must have an "
 						"explicitly defined binding number.";
@@ -417,8 +435,8 @@ namespace bs { namespace ct
 
 				GpuParamObjectDesc param;
 				param.name = name;
-				param.slot = ttype->getQualifier().layoutBinding;
-				param.set = ttype->getQualifier().layoutSet;
+				param.slot = qualifier.layoutBinding;
+				param.set = qualifier.layoutSet;
 
 				if (param.set == glslang::TQualifier::layoutSetEnd)
 					param.set = 0;
@@ -473,6 +491,10 @@ namespace bs { namespace ct
 			}
 			else
 			{
+				// We don't parse individual members of shared storage buffers
+				if (qualifier.storage == glslang::EvqBuffer)
+					continue;
+
 				if(ttype->getBasicType() == glslang::EbtStruct)
 				{
 					// Not handling structs at the moment
@@ -553,7 +575,7 @@ namespace bs { namespace ct
 		}
 		
 		TBuiltInResource resources = DefaultTBuiltInResource;
-		glslang::TProgram* program = new glslang::TProgram;
+		glslang::TProgram* program = bs_new<glslang::TProgram>();
 
 		EShLanguage glslType;
 		switch(mProperties.getType())
@@ -585,7 +607,7 @@ namespace bs { namespace ct
 		const String& source = mProperties.getSource();
 		const char* sourceBytes = source.c_str();
 
-		glslang::TShader* shader = new glslang::TShader(glslType);
+		glslang::TShader* shader = bs_new<glslang::TShader>(glslType);
 		shader->setStrings(&sourceBytes, 1);
 		shader->setEntryPoint("main");
 
@@ -666,8 +688,8 @@ namespace bs { namespace ct
 		mIsCompiled = true;
 
 cleanup:
-		delete program;
-		delete shader;
+		bs_delete(program);
+		bs_delete(shader);
 
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
 

+ 3 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanHardwareBuffer.cpp

@@ -108,6 +108,9 @@ namespace bs { namespace ct
 			usageFlags = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
 			mRequiresView = true;
 			break;
+		case BT_STRUCTURED:
+			usageFlags = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+			break;
 		}
 
 		mBufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;

+ 9 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanHardwareBufferManager.cpp

@@ -22,6 +22,9 @@ namespace bs { namespace ct
 
 		mDummyUniformBuffer = bs_new<VulkanHardwareBuffer>(
 			VulkanHardwareBuffer::BT_UNIFORM, BF_UNKNOWN, GBU_STATIC, 16, GDF_DEFAULT);
+
+		mDummyStructuredBuffer = bs_new<VulkanHardwareBuffer>(
+			VulkanHardwareBuffer::BT_STRUCTURED, BF_UNKNOWN, GBU_STATIC, 16, GDF_DEFAULT);
 	}
 
 	VulkanHardwareBufferManager::~VulkanHardwareBufferManager()
@@ -29,6 +32,7 @@ namespace bs { namespace ct
 		bs_delete(mDummyReadBuffer);
 		bs_delete(mDummyStorageBuffer);
 		bs_delete(mDummyUniformBuffer);
+		bs_delete(mDummyStructuredBuffer);
 	}
 
 	VkBufferView VulkanHardwareBufferManager::getDummyReadBufferView(UINT32 deviceIdx) const
@@ -46,6 +50,11 @@ namespace bs { namespace ct
 		return mDummyUniformBuffer->getResource(deviceIdx)->getHandle();
 	}
 
+	VkBuffer VulkanHardwareBufferManager::getDummyStructuredBuffer(UINT32 deviceIdx) const
+	{
+		return mDummyStructuredBuffer->getResource(deviceIdx)->getHandle();
+	}
+
 	SPtr<VertexBuffer> VulkanHardwareBufferManager::createVertexBufferInternal(const VERTEX_BUFFER_DESC& desc,
 		GpuDeviceFlags deviceMask)
 	{