Move state variables from Spirv to SpirvShader

This makes Spirv a purely SPIR-V binary parsing class, while SpirvShader
also holds the pipeline state which affects SPIR-V code emission at draw
time (which is provided at pipeline creation time).

Bug: b/247020580
Bug: b/253234336
Change-Id: Iaf3933c15981f64f8f5ffc8da72cd2a3b94879d5
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/68971
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 69b9922..8099e31 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -30,31 +30,13 @@
 Spirv::Spirv(
     VkShaderStageFlagBits pipelineStage,
     const char *entryPointName,
-    const SpirvBinary &insns,
-    const vk::RenderPass *renderPass,
-    uint32_t subpassIndex,
-    bool robustBufferAccess)
+    const SpirvBinary &insns)
     : insns{ insns }
     , inputs{ MAX_INTERFACE_COMPONENTS }
     , outputs{ MAX_INTERFACE_COMPONENTS }
-    , robustBufferAccess(robustBufferAccess)
 {
 	ASSERT(insns.size() > 0);
 
-	if(renderPass)
-	{
-		// capture formats of any input attachments present
-		auto subpass = renderPass->getSubpass(subpassIndex);
-		inputAttachmentFormats.reserve(subpass.inputAttachmentCount);
-		for(auto i = 0u; i < subpass.inputAttachmentCount; i++)
-		{
-			auto attachmentIndex = subpass.pInputAttachments[i].attachment;
-			inputAttachmentFormats.push_back(attachmentIndex != VK_ATTACHMENT_UNUSED
-			                                     ? renderPass->getAttachment(attachmentIndex).format
-			                                     : VK_FORMAT_UNDEFINED);
-		}
-	}
-
 	// The identifiers of all OpVariables that define the entry point's IO variables.
 	std::unordered_set<Object::ID> interfaceIds;
 
@@ -1716,7 +1698,7 @@
 	object.definition = insn;
 }
 
-OutOfBoundsBehavior Spirv::getOutOfBoundsBehavior(Object::ID pointerId, const vk::PipelineLayout *pipelineLayout) const
+OutOfBoundsBehavior SpirvShader::getOutOfBoundsBehavior(Object::ID pointerId, const vk::PipelineLayout *pipelineLayout) const
 {
 	auto it = descriptorDecorations.find(pointerId);
 	if(it != descriptorDecorations.end())
@@ -1770,7 +1752,7 @@
 
 // emit-time
 
-void Spirv::emitProlog(SpirvRoutine *routine) const
+void SpirvShader::emitProlog(SpirvRoutine *routine) const
 {
 	for(auto insn : *this)
 	{
@@ -1815,7 +1797,7 @@
 	}
 }
 
-void Spirv::emit(SpirvRoutine *routine, const RValue<SIMD::Int> &activeLaneMask, const RValue<SIMD::Int> &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount) const
+void SpirvShader::emit(SpirvRoutine *routine, const RValue<SIMD::Int> &activeLaneMask, const RValue<SIMD::Int> &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount) const
 {
 	SpirvEmitter::emit(*this, routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, multiSampleCount);
 }
@@ -1826,15 +1808,29 @@
                          const vk::RenderPass *renderPass,
                          uint32_t subpassIndex,
                          bool robustBufferAccess)
-    : Spirv(stage, entryPointName, insns, renderPass, subpassIndex, robustBufferAccess)
+    : Spirv(stage, entryPointName, insns)
+    , robustBufferAccess(robustBufferAccess)
 {
+	if(renderPass)
+	{
+		// capture formats of any input attachments present
+		auto subpass = renderPass->getSubpass(subpassIndex);
+		inputAttachmentFormats.reserve(subpass.inputAttachmentCount);
+		for(auto i = 0u; i < subpass.inputAttachmentCount; i++)
+		{
+			auto attachmentIndex = subpass.pInputAttachments[i].attachment;
+			inputAttachmentFormats.push_back(attachmentIndex != VK_ATTACHMENT_UNUSED
+			                                     ? renderPass->getAttachment(attachmentIndex).format
+			                                     : VK_FORMAT_UNDEFINED);
+		}
+	}
 }
 
 SpirvShader::~SpirvShader()
 {
 }
 
-SpirvEmitter::SpirvEmitter(const Spirv &shader,
+SpirvEmitter::SpirvEmitter(const SpirvShader &shader,
                            SpirvRoutine *routine,
                            Spirv::Function::ID entryPoint,
                            RValue<SIMD::Int> activeLaneMask,
@@ -1851,7 +1847,7 @@
 {
 }
 
-void SpirvEmitter::emit(const Spirv &shader,
+void SpirvEmitter::emit(const SpirvShader &shader,
                         SpirvRoutine *routine,
                         Spirv::Function::ID entryPoint,
                         RValue<SIMD::Int> activeLaneMask,
@@ -2722,7 +2718,7 @@
 	return scopeObj.constantValue[0];
 }
 
-void Spirv::emitEpilog(SpirvRoutine *routine) const
+void SpirvShader::emitEpilog(SpirvRoutine *routine) const
 {
 	for(auto insn : *this)
 	{
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 7555aba..3cd438a 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -146,15 +146,14 @@
 #endif  // ENABLE_RR_PRINT
 };
 
+// The Spirv class parses a SPIR-V binary and provides utilities for retrieving
+// information about instructions, objects, types, etc.
 class Spirv
 {
 public:
 	Spirv(VkShaderStageFlagBits stage,
 	      const char *entryPointName,
-	      const SpirvBinary &insns,
-	      const vk::RenderPass *renderPass,
-	      uint32_t subpassIndex,
-	      bool robustBufferAccess);
+	      const SpirvBinary &insns);
 
 	~Spirv();
 
@@ -753,7 +752,6 @@
 	};
 
 	std::unordered_map<Object::ID, DescriptorDecorations> descriptorDecorations;
-	std::vector<vk::Format> inputAttachmentFormats;
 
 	struct InterfaceComponent
 	{
@@ -813,25 +811,15 @@
 	std::vector<InterfaceComponent> inputs;
 	std::vector<InterfaceComponent> outputs;
 
-	// TODO(b/247020580): Move to SpirvRoutine
-	void emitProlog(SpirvRoutine *routine) const;
-	void emit(SpirvRoutine *routine, const RValue<SIMD::Int> &activeLaneMask, const RValue<SIMD::Int> &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount = 0) const;
-	void emitEpilog(SpirvRoutine *routine) const;
-
 	uint32_t getWorkgroupSizeX() const;
 	uint32_t getWorkgroupSizeY() const;
 	uint32_t getWorkgroupSizeZ() const;
 
-	bool getRobustBufferAccess() const { return robustBufferAccess; }
-
 	using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
 	std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins;
 	std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins;
 	WorkgroupMemory workgroupMemory;
 
-private:
-	const bool robustBufferAccess;
-
 	Function::ID entryPoint;
 	spv::ExecutionModel executionModel = spv::ExecutionModelMax;  // Invalid prior to OpEntryPoint parsing.
 	ExecutionModes executionModes = {};
@@ -940,8 +928,6 @@
 		return it->second;
 	}
 
-	OutOfBoundsBehavior getOutOfBoundsBehavior(Object::ID pointerId, const vk::PipelineLayout *pipelineLayout) const;
-
 	// Returns the *component* offset in the literal for the given access chain.
 	uint32_t WalkLiteralAccessChain(Type::ID id, const Span &indexes) const;
 
@@ -979,7 +965,8 @@
 	static bool IsTerminator(spv::Op opcode);
 };
 
-// TODO(b/247020580): Move state from Spirv to SpirvShader
+// The SpirvShader class holds a parsed SPIR-V shader but also the pipeline
+// state which affects code emission when passing it to SpirvEmitter.
 class SpirvShader : public Spirv
 {
 public:
@@ -991,6 +978,21 @@
 	            bool robustBufferAccess);
 
 	~SpirvShader();
+
+	// TODO(b/247020580): Move to SpirvRoutine
+	void emitProlog(SpirvRoutine *routine) const;
+	void emit(SpirvRoutine *routine, const RValue<SIMD::Int> &activeLaneMask, const RValue<SIMD::Int> &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount = 0) const;
+	void emitEpilog(SpirvRoutine *routine) const;
+
+	bool getRobustBufferAccess() const { return robustBufferAccess; }
+	OutOfBoundsBehavior getOutOfBoundsBehavior(Object::ID pointerId, const vk::PipelineLayout *pipelineLayout) const;
+
+	vk::Format getInputAttachmentFormat(int32_t index) const { return inputAttachmentFormats[index]; }
+
+private:
+	const bool robustBufferAccess;
+
+	std::vector<vk::Format> inputAttachmentFormats;
 };
 
 // The SpirvEmitter class translates the parsed SPIR-V shader into Reactor code.
@@ -1004,7 +1006,7 @@
 	using Span = Spirv::Span;
 
 public:
-	static void emit(const Spirv &shader,
+	static void emit(const SpirvShader &shader,
 	                 SpirvRoutine *routine,
 	                 Spirv::Function::ID entryPoint,
 	                 RValue<SIMD::Int> activeLaneMask,
@@ -1019,7 +1021,7 @@
 	};
 
 private:
-	SpirvEmitter(const Spirv &shader,
+	SpirvEmitter(const SpirvShader &shader,
 	             SpirvRoutine *routine,
 	             Spirv::Function::ID entryPoint,
 	             RValue<SIMD::Int> activeLaneMask,
@@ -1519,7 +1521,7 @@
 	static sw::MipmapType convertMipmapMode(const vk::SamplerState *samplerState);
 	static sw::AddressingMode convertAddressingMode(int coordinateIndex, const vk::SamplerState *samplerState, VkImageViewType imageViewType);
 
-	const Spirv &shader;
+	const SpirvShader &shader;
 	SpirvRoutine *const routine;                     // The current routine being built.
 	Spirv::Function::ID function;                    // The current function being built.
 	Block::ID block;                                 // The current block being built.
diff --git a/src/Pipeline/SpirvShaderImage.cpp b/src/Pipeline/SpirvShaderImage.cpp
index ef2d30e..a4b5570 100644
--- a/src/Pipeline/SpirvShaderImage.cpp
+++ b/src/Pipeline/SpirvShaderImage.cpp
@@ -835,7 +835,7 @@
 	// For subpass data, format in the instruction is spv::ImageFormatUnknown. Get it from
 	// the renderpass data instead. In all other cases, we can use the format in the instruction.
 	vk::Format imageFormat = (dim == spv::DimSubpassData)
-	                             ? shader.inputAttachmentFormats[d.InputAttachmentIndex]
+	                             ? shader.getInputAttachmentFormat(d.InputAttachmentIndex)
 	                             : SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(instruction.imageFormat));
 
 	// Depth+Stencil image attachments select aspect based on the Sampled Type of the