Plumb PipelineLayouts down to SpirvRoutine

This initializes arrays to hold the descriptor sets in the routine. Nothing uses this yet.

Bug: b/126330097
Change-Id: If052d0b93e62e4f32e88ed02f9bc21f4203587f5
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/25553
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp
index face9e4..53a7772 100644
--- a/src/Device/Context.cpp
+++ b/src/Device/Context.cpp
@@ -218,6 +218,8 @@
 			colorWriteMask[i] = 0x0000000F;
 		}
 
+		pipelineLayout = nullptr;
+
 		pixelShader = nullptr;
 		vertexShader = nullptr;
 
diff --git a/src/Device/Context.hpp b/src/Device/Context.hpp
index db14e8c..6be2017 100644
--- a/src/Device/Context.hpp
+++ b/src/Device/Context.hpp
@@ -24,7 +24,8 @@
 namespace vk
 {
 	class ImageView;
-};
+	class PipelineLayout;
+} // namespace vk
 
 namespace sw
 {
@@ -198,6 +199,8 @@
 		vk::ImageView *stencilBuffer;
 		unsigned int stencilBufferLayer;
 
+		vk::PipelineLayout const *pipelineLayout;
+
 		// Shaders
 		const SpirvShader *pixelShader;
 		const SpirvShader *vertexShader;
diff --git a/src/Device/PixelProcessor.cpp b/src/Device/PixelProcessor.cpp
index cc52c87..811a265 100644
--- a/src/Device/PixelProcessor.cpp
+++ b/src/Device/PixelProcessor.cpp
@@ -449,7 +449,7 @@
 
 		if(!routine)
 		{
-			QuadRasterizer *generator = new PixelProgram(state, context->pixelShader);
+			QuadRasterizer *generator = new PixelProgram(state, context->pipelineLayout, context->pixelShader);
 			generator->generate();
 			routine = (*generator)("PixelRoutine_%0.8X", state.shaderID);
 			delete generator;
diff --git a/src/Device/VertexProcessor.cpp b/src/Device/VertexProcessor.cpp
index 065e7c0..21ab83f 100644
--- a/src/Device/VertexProcessor.cpp
+++ b/src/Device/VertexProcessor.cpp
@@ -129,7 +129,7 @@
 
 		if(!routine)   // Create one
 		{
-			VertexRoutine *generator = new VertexProgram(state, context->vertexShader);
+			VertexRoutine *generator = new VertexProgram(state, context->pipelineLayout, context->vertexShader);
 			generator->generate();
 			routine = (*generator)("VertexRoutine_%0.8X", state.shaderID);
 			delete generator;
diff --git a/src/Pipeline/PixelProgram.hpp b/src/Pipeline/PixelProgram.hpp
index 2959418..71c46df 100644
--- a/src/Pipeline/PixelProgram.hpp
+++ b/src/Pipeline/PixelProgram.hpp
@@ -23,8 +23,11 @@
 	class PixelProgram : public PixelRoutine
 	{
 	public:
-		PixelProgram(const PixelProcessor::State &state, SpirvShader const *spirvShader) :
-			PixelRoutine(state, spirvShader)
+		PixelProgram(
+				const PixelProcessor::State &state,
+				vk::PipelineLayout const *pipelineLayout,
+				SpirvShader const *spirvShader) :
+			PixelRoutine(state, pipelineLayout, spirvShader)
 		{
 		}
 
diff --git a/src/Pipeline/PixelRoutine.cpp b/src/Pipeline/PixelRoutine.cpp
index ce32f32..fd6a85c 100644
--- a/src/Pipeline/PixelRoutine.cpp
+++ b/src/Pipeline/PixelRoutine.cpp
@@ -29,8 +29,12 @@
 	extern bool exactColorRounding;
 	extern bool forceClearRegisters;
 
-	PixelRoutine::PixelRoutine(const PixelProcessor::State &state, SpirvShader const *spirvShader)
-		: QuadRasterizer(state, spirvShader)	/* addressing */
+	PixelRoutine::PixelRoutine(
+			const PixelProcessor::State &state,
+			vk::PipelineLayout const *pipelineLayout,
+			SpirvShader const *spirvShader)
+		: QuadRasterizer(state, spirvShader),
+		  routine(pipelineLayout)
 	{
 		spirvShader->emitProlog(&routine);
 
diff --git a/src/Pipeline/PixelRoutine.hpp b/src/Pipeline/PixelRoutine.hpp
index a2b2b6e..7b8f780 100644
--- a/src/Pipeline/PixelRoutine.hpp
+++ b/src/Pipeline/PixelRoutine.hpp
@@ -25,7 +25,9 @@
 	class PixelRoutine : public sw::QuadRasterizer, public ShaderCore
 	{
 	public:
-		PixelRoutine(const PixelProcessor::State &state, SpirvShader const *spirvShader);
+		PixelRoutine(const PixelProcessor::State &state,
+			vk::PipelineLayout const *pipelineLayout,
+			SpirvShader const *spirvShader);
 
 		virtual ~PixelRoutine();
 
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 77d3393..d3c0061 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -16,6 +16,7 @@
 #include "SpirvShader.hpp"
 #include "System/Math.hpp"
 #include "Vulkan/VkDebug.hpp"
+#include "Vulkan/VkPipelineLayout.hpp"
 #include "Device/Config.hpp"
 
 namespace sw
@@ -1437,4 +1438,10 @@
 			}
 		}
 	}
+
+	SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
+		pipelineLayout(pipelineLayout)
+	{
+	}
+
 }
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index ecac7a7..76400c0 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -15,11 +15,13 @@
 #ifndef sw_SpirvShader_hpp
 #define sw_SpirvShader_hpp
 
-#include "System/Types.hpp"
-#include "Vulkan/VkDebug.hpp"
 #include "ShaderCore.hpp"
 #include "SpirvID.hpp"
+#include "System/Types.hpp"
+#include "Vulkan/VkDebug.hpp"
+#include "Vulkan/VkConfig.h"
 
+#include <array>
 #include <cstring>
 #include <string>
 #include <vector>
@@ -30,6 +32,11 @@
 #include <spirv/unified1/spirv.hpp>
 #include <Device/Config.hpp>
 
+namespace vk
+{
+	class PipelineLayout;
+} // namespace vk
+
 namespace sw
 {
 	// Forward declarations.
@@ -412,8 +419,12 @@
 	class SpirvRoutine
 	{
 	public:
+		SpirvRoutine(vk::PipelineLayout const *pipelineLayout);
+
 		using Value = Array<SIMD::Float>;
 
+		vk::PipelineLayout const * const pipelineLayout;
+
 		std::unordered_map<SpirvShader::ObjectID, Value> lvalues;
 
 		std::unordered_map<SpirvShader::ObjectID, Intermediate> intermediates;
@@ -421,6 +432,8 @@
 		Value inputs = Value{MAX_INTERFACE_COMPONENTS};
 		Value outputs = Value{MAX_INTERFACE_COMPONENTS};
 
+		std::array<Pointer<Byte>, vk::MAX_BOUND_DESCRIPTOR_SETS> descriptorSets;
+
 		void createLvalue(SpirvShader::ObjectID id, uint32_t size)
 		{
 			lvalues.emplace(id, Value(size));
diff --git a/src/Pipeline/VertexProgram.cpp b/src/Pipeline/VertexProgram.cpp
index 56eb4ce..182e7bd 100644
--- a/src/Pipeline/VertexProgram.cpp
+++ b/src/Pipeline/VertexProgram.cpp
@@ -22,8 +22,11 @@
 
 namespace sw
 {
-	VertexProgram::VertexProgram(const VertexProcessor::State &state, SpirvShader const *spirvShader)
-		: VertexRoutine(state, spirvShader)
+	VertexProgram::VertexProgram(
+			const VertexProcessor::State &state,
+			vk::PipelineLayout const *pipelineLayout,
+			SpirvShader const *spirvShader)
+		: VertexRoutine(state, pipelineLayout, spirvShader)
 	{
 		ifDepth = 0;
 		loopRepDepth = 0;
diff --git a/src/Pipeline/VertexProgram.hpp b/src/Pipeline/VertexProgram.hpp
index 358ed5f..5fe1252 100644
--- a/src/Pipeline/VertexProgram.hpp
+++ b/src/Pipeline/VertexProgram.hpp
@@ -29,7 +29,10 @@
 	class VertexProgram : public VertexRoutine, public ShaderCore
 	{
 	public:
-		VertexProgram(const VertexProcessor::State &state, SpirvShader const *spirvShader);
+		VertexProgram(
+			const VertexProcessor::State &state,
+			vk::PipelineLayout const *pipelineLayout,
+			SpirvShader const *spirvShader);
 
 		virtual ~VertexProgram();
 
diff --git a/src/Pipeline/VertexRoutine.cpp b/src/Pipeline/VertexRoutine.cpp
index c4e5db5..df2c813 100644
--- a/src/Pipeline/VertexRoutine.cpp
+++ b/src/Pipeline/VertexRoutine.cpp
@@ -24,8 +24,12 @@
 
 namespace sw
 {
-	VertexRoutine::VertexRoutine(const VertexProcessor::State &state, SpirvShader const *spirvShader)
-		: state(state),
+	VertexRoutine::VertexRoutine(
+			const VertexProcessor::State &state,
+			vk::PipelineLayout const *pipelineLayout,
+			SpirvShader const *spirvShader)
+		: routine(pipelineLayout),
+		  state(state),
 		  spirvShader(spirvShader)
 	{
 	  	spirvShader->emitProlog(&routine);
diff --git a/src/Pipeline/VertexRoutine.hpp b/src/Pipeline/VertexRoutine.hpp
index 943e560..757fc51 100644
--- a/src/Pipeline/VertexRoutine.hpp
+++ b/src/Pipeline/VertexRoutine.hpp
@@ -20,6 +20,11 @@
 #include "ShaderCore.hpp"
 #include "SpirvShader.hpp"
 
+namespace vk
+{
+	class PipelineLayout;
+} // namespace vk
+
 namespace sw
 {
 	class VertexRoutinePrototype : public Function<Void(Pointer<Byte>, Pointer<Byte>, Pointer<Byte>, Pointer<Byte>)>
@@ -38,7 +43,10 @@
 	class VertexRoutine : public VertexRoutinePrototype
 	{
 	public:
-		VertexRoutine(const VertexProcessor::State &state, SpirvShader const *spirvShader);
+		VertexRoutine(
+			const VertexProcessor::State &state,
+			vk::PipelineLayout const *pipelineLayout,
+			SpirvShader const *spirvShader);
 		virtual ~VertexRoutine();
 
 		void generate();
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index d07e27b..14f43a8 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -13,6 +13,8 @@
 // limitations under the License.
 
 #include "VkDescriptorSetLayout.hpp"
+#include "System/Types.hpp"
+
 #include <algorithm>
 #include <cstring>
 
@@ -176,6 +178,12 @@
 	}
 }
 
+size_t DescriptorSetLayout::getBindingOffset(uint32_t binding) const
+{
+	uint32_t index = getBindingIndex(binding);
+	return bindingOffsets[index] + OFFSET(DescriptorSet, data[0]);
+}
+
 uint8_t* DescriptorSetLayout::getOffsetPointer(VkDescriptorSet descriptorSet, uint32_t binding, uint32_t arrayElement, uint32_t count, size_t* typeSize) const
 {
 	uint32_t index = getBindingIndex(binding);
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp
index 627c9ab..d332c28 100644
--- a/src/Vulkan/VkDescriptorSetLayout.hpp
+++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -35,6 +35,7 @@
 
 	void initialize(VkDescriptorSet descriptorSet);
 	size_t getSize() const;
+	size_t getBindingOffset(uint32_t binding) const;
 
 private:
 	uint32_t getBindingIndex(uint32_t binding) const;
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index b2eac40..a446e64 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "VkPipeline.hpp"
+#include "VkPipelineLayout.hpp"
 #include "VkShaderModule.hpp"
 #include "Pipeline/SpirvShader.hpp"
 
@@ -191,7 +192,10 @@
 namespace vk
 {
 
+Pipeline::Pipeline(PipelineLayout const *layout) : layout(layout) {}
+
 GraphicsPipeline::GraphicsPipeline(const VkGraphicsPipelineCreateInfo* pCreateInfo, void* mem)
+	: Pipeline(Cast(pCreateInfo->layout))
 {
 	if((pCreateInfo->flags != 0) ||
 	   (pCreateInfo->stageCount != 2) ||
@@ -230,6 +234,9 @@
 		UNIMPLEMENTED();
 	}
 
+	// Context must always have a PipelineLayout set.
+	context.pipelineLayout = layout;
+
 	// Temporary in-binding-order representation of buffer strides, to be consumed below
 	// when considering attributes. TODO: unfuse buffers from attributes in backend, is old GL model.
 	uint32_t bufferStrides[MAX_VERTEX_INPUT_BINDINGS];
@@ -499,6 +506,7 @@
 }
 
 ComputePipeline::ComputePipeline(const VkComputePipelineCreateInfo* pCreateInfo, void* mem)
+	: Pipeline(Cast(pCreateInfo->layout))
 {
 }
 
diff --git a/src/Vulkan/VkPipeline.hpp b/src/Vulkan/VkPipeline.hpp
index 039b33e..7b4d591 100644
--- a/src/Vulkan/VkPipeline.hpp
+++ b/src/Vulkan/VkPipeline.hpp
@@ -23,9 +23,13 @@
 namespace vk
 {
 
+class PipelineLayout;
+
 class Pipeline
 {
 public:
+	Pipeline(PipelineLayout const *layout);
+
 	operator VkPipeline()
 	{
 		return reinterpret_cast<VkPipeline>(this);
@@ -40,6 +44,11 @@
 #ifndef NDEBUG
 	virtual VkPipelineBindPoint bindPoint() const = 0;
 #endif
+
+	PipelineLayout const * getLayout() const { return layout; }
+
+protected:
+	PipelineLayout const *layout = nullptr;
 };
 
 class GraphicsPipeline : public Pipeline, public ObjectBase<GraphicsPipeline, VkPipeline>
diff --git a/src/Vulkan/VkPipelineLayout.cpp b/src/Vulkan/VkPipelineLayout.cpp
index 1daea01..fcc6c66 100644
--- a/src/Vulkan/VkPipelineLayout.cpp
+++ b/src/Vulkan/VkPipelineLayout.cpp
@@ -44,4 +44,15 @@
 	       (pCreateInfo->pushConstantRangeCount * sizeof(VkPushConstantRange));
 }
 
+size_t PipelineLayout::getNumDescriptorSets() const
+{
+	return setLayoutCount;
+}
+
+size_t PipelineLayout::getBindingOffset(size_t descriptorSet, size_t binding) const
+{
+	ASSERT(descriptorSet < setLayoutCount);
+	return setLayouts[descriptorSet]->getBindingOffset(binding);
+}
+
 } // namespace vk
diff --git a/src/Vulkan/VkPipelineLayout.hpp b/src/Vulkan/VkPipelineLayout.hpp
index fe9d528..5723317 100644
--- a/src/Vulkan/VkPipelineLayout.hpp
+++ b/src/Vulkan/VkPipelineLayout.hpp
@@ -29,6 +29,9 @@
 
 	static size_t ComputeRequiredAllocationSize(const VkPipelineLayoutCreateInfo* pCreateInfo);
 
+	size_t getNumDescriptorSets() const;
+	size_t getBindingOffset(size_t descriptorSet, size_t binding) const;
+
 private:
 	uint32_t              setLayoutCount = 0;
 	DescriptorSetLayout** setLayouts = nullptr;