SpirvShader: Don't abort for unused, unbound UniformConstants

Bug: b/126330097
Tests: dEQP-VK.glsl.discard.*
Change-Id: I17632f68705aa8f0c8c607b5ec469272a58047db
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29908
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 073f0da..60ba39b 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -1345,6 +1345,7 @@
 				auto set = routine->getPointer(id);
 
 				auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
+				ASSERT_MSG(setLayout->hasBinding(d.Binding), "Descriptor set %d does not contain binding %d", int(d.DescriptorSet), int(d.Binding));
 				int bindingOffset = static_cast<int>(setLayout->getBindingOffset(d.Binding, arrayIndex));
 
 				Pointer<Byte> descriptor = set.base + bindingOffset; // BufferDescriptor*
@@ -2501,11 +2502,20 @@
 
 			uint32_t arrayIndex = 0;  // TODO(b/129523279)
 			auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
-			size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex);
-			Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet];  // DescriptorSet*
-			Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset);    // vk::SampledImageDescriptor*
-			auto size = 0; // Not required as this pointer is not directly used by SIMD::Read or SIMD::Write.
-			routine->createPointer(resultId, SIMD::Pointer(binding, size));
+			if (setLayout->hasBinding(d.Binding))
+			{
+				size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex);
+				Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet];  // DescriptorSet*
+				Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset);    // vk::SampledImageDescriptor*
+				auto size = 0; // Not required as this pointer is not directly used by SIMD::Read or SIMD::Write.
+				routine->createPointer(resultId, SIMD::Pointer(binding, size));
+			}
+			else
+			{
+				// TODO: Error if the variable with the non-existant binding is
+				// used? Or perhaps strip these unused variable declarations as
+				// a preprocess on the SPIR-V?
+			}
 			break;
 		}
 		case spv::StorageClassUniform:
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index da86116..b84079c 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -175,6 +175,18 @@
 	return bindingCount;
 }
 
+bool DescriptorSetLayout::hasBinding(uint32_t binding) const
+{
+	for(uint32_t i = 0; i < bindingCount; i++)
+	{
+		if(binding == bindings[i].binding)
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
 size_t DescriptorSetLayout::getBindingStride(uint32_t binding) const
 {
 	uint32_t index = getBindingIndex(binding);
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp
index be92b4e..627922a 100644
--- a/src/Vulkan/VkDescriptorSetLayout.hpp
+++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -78,6 +78,9 @@
 	// Returns the number of bindings in the descriptor set.
 	size_t getBindingCount() const;
 
+	// Returns true iff the given binding exists.
+	bool hasBinding(uint32_t binding) const;
+
 	// Returns the byte offset from the base address of the descriptor set for
 	// the given binding and array element within that binding.
 	size_t getBindingOffset(uint32_t binding, size_t arrayElement) const;