Add tests for uniform block linking by binding

Drivers should ignore uniform block name debug opcodes when doing
linking and instead expect matching by binding only. Test this by
declaring different uniform blocks with same name but different bindings
in vertex and fragment shaders.

Bug: 28857593
Change-Id: I4a84b4de2021802fd247cd744d01491eb8224bd4
diff --git a/android/cts/master/com.drawelements.deqp.vk.xml b/android/cts/master/com.drawelements.deqp.vk.xml
index 1a42095..e3bc90b 100644
--- a/android/cts/master/com.drawelements.deqp.vk.xml
+++ b/android/cts/master/com.drawelements.deqp.vk.xml
@@ -252422,6 +252422,20 @@
 					</Test>
 				</TestCase>
 			</TestSuite>
+			<TestCase name="link_by_binding">
+				<Test name="single_buf_single_instance">
+					<TestInstance/>
+				</Test>
+				<Test name="single_buf_instance_array">
+					<TestInstance/>
+				</Test>
+				<Test name="per_block_buf_single_instance">
+					<TestInstance/>
+				</Test>
+				<Test name="per_block_buf_instance_array">
+					<TestInstance/>
+				</Test>
+			</TestCase>
 			<TestSuite name="random">
 				<TestCase name="scalar_types">
 					<Test name="0">
diff --git a/android/cts/master/vk-master.txt b/android/cts/master/vk-master.txt
index df1b257..e59c4a7 100644
--- a/android/cts/master/vk-master.txt
+++ b/android/cts/master/vk-master.txt
@@ -78248,6 +78248,10 @@
 dEQP-VK.ubo.multi_nested_struct.single_buffer.std140_instance_array_fragment
 dEQP-VK.ubo.multi_nested_struct.single_buffer.std140_instance_array_both
 dEQP-VK.ubo.multi_nested_struct.single_buffer.std140_instance_array_mixed
+dEQP-VK.ubo.link_by_binding.single_buf_single_instance
+dEQP-VK.ubo.link_by_binding.single_buf_instance_array
+dEQP-VK.ubo.link_by_binding.per_block_buf_single_instance
+dEQP-VK.ubo.link_by_binding.per_block_buf_instance_array
 dEQP-VK.ubo.random.scalar_types.0
 dEQP-VK.ubo.random.scalar_types.1
 dEQP-VK.ubo.random.scalar_types.2
diff --git a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.cpp b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.cpp
index 0313e56..35805fb 100644
--- a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.cpp
+++ b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.cpp
@@ -165,7 +165,7 @@
 {
 	stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
 		   << ", size = " << entry.size
-		   << ", blockNdx = " << entry.blockNdx
+		   << ", blockNdx = " << entry.blockLayoutNdx
 		   << ", offset = " << entry.offset
 		   << ", arrayStride = " << entry.arrayStride
 		   << ", matrixStride = " << entry.matrixStride
@@ -174,22 +174,24 @@
 	return stream;
 }
 
-int UniformLayout::getUniformIndex (const std::string& name) const
+int UniformLayout::getUniformLayoutIndex (int blockNdx, const std::string& name) const
 {
 	for (int ndx = 0; ndx < (int)uniforms.size(); ndx++)
 	{
-		if (uniforms[ndx].name == name)
+		if (blocks[uniforms[ndx].blockLayoutNdx].blockDeclarationNdx == blockNdx &&
+			uniforms[ndx].name == name)
 			return ndx;
 	}
 
 	return -1;
 }
 
-int UniformLayout::getBlockIndex (const std::string& name) const
+int UniformLayout::getBlockLayoutIndex (int blockNdx, int instanceNdx) const
 {
 	for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
 	{
-		if (blocks[ndx].name == name)
+		if (blocks[ndx].blockDeclarationNdx == blockNdx &&
+			blocks[ndx].instanceNdx == instanceNdx)
 			return ndx;
 	}
 
@@ -423,7 +425,7 @@
 		entry.size			= 1;
 		entry.arrayStride	= 0;
 		entry.matrixStride	= 0;
-		entry.blockNdx		= curBlockNdx;
+		entry.blockLayoutNdx= curBlockNdx;
 
 		if (glu::isDataTypeMatrix(basicType))
 		{
@@ -464,7 +466,7 @@
 
 			entry.name			= curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
 			entry.type			= elemBasicType;
-			entry.blockNdx		= curBlockNdx;
+			entry.blockLayoutNdx= curBlockNdx;
 			entry.offset		= curOffset;
 			entry.size			= type.getArraySize();
 			entry.arrayStride	= stride;
@@ -488,7 +490,7 @@
 
 			entry.name			= curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
 			entry.type			= elemBasicType;
-			entry.blockNdx		= curBlockNdx;
+			entry.blockLayoutNdx= curBlockNdx;
 			entry.offset		= curOffset;
 			entry.size			= type.getArraySize();
 			entry.arrayStride	= stride*numVecs;
@@ -551,6 +553,7 @@
 			blockEntry.name = block.getBlockName();
 			blockEntry.size = blockSize;
 			blockEntry.bindingNdx = blockNdx;
+			blockEntry.blockDeclarationNdx = blockNdx;
 			blockEntry.instanceNdx = instanceNdx;
 
 			// Compute active uniform set for block.
@@ -946,6 +949,7 @@
 						 const std::string&		srcName,
 						 const std::string&		apiName,
 						 const UniformLayout&	layout,
+						 int					blockNdx,
 						 const void*			basePtr,
 						 deUint32				unusedMask)
 {
@@ -956,7 +960,7 @@
 		glu::DataType				elementType		= isArray ? type.getElementType().getBasicType() : type.getBasicType();
 		const char*					typeName		= glu::getDataTypeName(elementType);
 		std::string					fullApiName		= std::string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
-		int							uniformNdx		= layout.getUniformIndex(fullApiName);
+		int							uniformNdx		= layout.getUniformLayoutIndex(blockNdx, fullApiName);
 		const UniformLayoutEntry&	entry			= layout.uniforms[uniformNdx];
 
 		if (isArray)
@@ -984,7 +988,7 @@
 			std::string op = std::string("[") + de::toString(elementNdx) + "]";
 			std::string elementSrcName = std::string(srcName) + op;
 			std::string elementApiName = std::string(apiName) + op;
-			generateCompareSrc(src, resultVar, elementType, elementSrcName, elementApiName, layout, basePtr, unusedMask);
+			generateCompareSrc(src, resultVar, elementType, elementSrcName, elementApiName, layout, blockNdx, basePtr, unusedMask);
 		}
 	}
 	else
@@ -999,7 +1003,7 @@
 			std::string op = std::string(".") + memberIter->getName();
 			std::string memberSrcName = std::string(srcName) + op;
 			std::string memberApiName = std::string(apiName) + op;
-			generateCompareSrc(src, resultVar, memberIter->getType(), memberSrcName, memberApiName, layout, basePtr, unusedMask);
+			generateCompareSrc(src, resultVar, memberIter->getType(), memberSrcName, memberApiName, layout, blockNdx, basePtr, unusedMask);
 		}
 	}
 }
@@ -1027,8 +1031,8 @@
 			std::string		instancePostfix		= isArray ? std::string("[") + de::toString(instanceNdx) + "]" : std::string("");
 			std::string		blockInstanceName	= block.getBlockName() + instancePostfix;
 			std::string		srcPrefix			= hasInstanceName ? block.getInstanceName() + instancePostfix + "." : std::string("");
-			int				activeBlockNdx		= layout.getBlockIndex(blockInstanceName);
-			void*			basePtr				= blockPointers.find(activeBlockNdx)->second;
+			int				blockLayoutNdx		= layout.getBlockLayoutIndex(blockNdx, instanceNdx);
+			void*			basePtr				= blockPointers.find(blockLayoutNdx)->second;
 
 			for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
 			{
@@ -1039,7 +1043,7 @@
 
 				std::string srcName = srcPrefix + uniform.getName();
 				std::string apiName = apiPrefix + uniform.getName();
-				generateCompareSrc(src, resultVar, uniform.getType(), srcName, apiName, layout, basePtr, unusedMask);
+				generateCompareSrc(src, resultVar, uniform.getType(), srcName, apiName, layout, blockNdx, basePtr, unusedMask);
 			}
 		}
 	}
diff --git a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.hpp b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.hpp
index 2fd9e1f..d369288 100644
--- a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.hpp
+++ b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockCase.hpp
@@ -234,13 +234,17 @@
 struct BlockLayoutEntry
 {
 	BlockLayoutEntry (void)
-		: size(0)
+		: size					(0)
+		, blockDeclarationNdx	(-1)
+		, bindingNdx			(-1)
+		, instanceNdx			(-1)
 	{
 	}
 
 	std::string			name;
 	int					size;
 	std::vector<int>	activeUniformIndices;
+	int					blockDeclarationNdx;
 	int					bindingNdx;
 	int					instanceNdx;
 };
@@ -250,7 +254,7 @@
 	UniformLayoutEntry (void)
 		: type			(glu::TYPE_LAST)
 		, size			(0)
-		, blockNdx		(-1)
+		, blockLayoutNdx(-1)
 		, offset		(-1)
 		, arrayStride	(-1)
 		, matrixStride	(-1)
@@ -262,7 +266,7 @@
 	std::string			name;
 	glu::DataType		type;
 	int					size;
-	int					blockNdx;
+	int					blockLayoutNdx;
 	int					offset;
 	int					arrayStride;
 	int					matrixStride;
@@ -276,8 +280,8 @@
 	std::vector<BlockLayoutEntry>		blocks;
 	std::vector<UniformLayoutEntry>		uniforms;
 
-	int									getUniformIndex			(const std::string& name) const;
-	int									getBlockIndex			(const std::string& name) const;
+	int									getUniformLayoutIndex	(int blockDeclarationNdx, const std::string& name) const;
+	int									getBlockLayoutIndex		(int blockDeclarationNdx, int instanceNdx) const;
 };
 
 class UniformBlockCase : public vkt::TestCase
diff --git a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.cpp b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.cpp
index 22595d9..e5e6b47 100644
--- a/external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.cpp
+++ b/external/vulkancts/modules/vulkan/ubo/vktUniformBlockTests.cpp
@@ -287,6 +287,37 @@
 	int			m_numInstances;
 };
 
+class LinkByBindingCase : public UniformBlockCase
+{
+public:
+	LinkByBindingCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, BufferMode bufferMode, int numInstances)
+		: UniformBlockCase	(testCtx, name, description, bufferMode)
+	{
+		UniformBlock& blockA = m_interface.allocBlock("TestBlock");
+		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
+		blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
+		blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
+		blockA.setFlags(LAYOUT_STD140|DECLARE_VERTEX);
+
+		UniformBlock& blockB = m_interface.allocBlock("TestBlock");
+		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
+		blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
+		blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
+		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
+		blockB.setFlags(LAYOUT_STD140|DECLARE_FRAGMENT);
+
+		if (numInstances > 0)
+		{
+			blockA.setInstanceName("testBlock");
+			blockA.setArraySize(numInstances);
+			blockB.setInstanceName("testBlock");
+			blockB.setArraySize(numInstances);
+		}
+
+		init();
+	}
+};
+
 void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, tcu::TestContext& testCtx, const char* groupName, const char* description, UniformBlockCase::BufferMode bufferMode, deUint32 features, int numCases, deUint32 baseSeed)
 {
 	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(testCtx, groupName, description);
@@ -770,6 +801,17 @@
 		}
 	}
 
+	// .link_by_binding
+	{
+		tcu::TestCaseGroup* linkByBindingGroup = new tcu::TestCaseGroup(m_testCtx, "link_by_binding", "Blocks with same name but different binding");
+		addChild(linkByBindingGroup);
+
+		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "single_buf_single_instance",		"", UniformBlockCase::BUFFERMODE_SINGLE, 0));
+		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "single_buf_instance_array",		"", UniformBlockCase::BUFFERMODE_SINGLE, 2));
+		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "per_block_buf_single_instance",	"", UniformBlockCase::BUFFERMODE_PER_BLOCK, 0));
+		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "per_block_buf_instance_array",	"", UniformBlockCase::BUFFERMODE_PER_BLOCK, 2));
+	}
+
 	// ubo.random
 	{
 		const deUint32	allShaders		= FEATURE_VERTEX_BLOCKS|FEATURE_FRAGMENT_BLOCKS|FEATURE_SHARED_BLOCKS;