Pipeline: Store builtins on SpirvRoutine...

... even if they're not directly used by the SPIR-V shader code.
This will let the debugger display these values in the locals window.

Bug: b/145351270
Change-Id: I1d390e95bf38e89b072ef374e6a35cd8222a45c6
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38912
Tested-by: Ben Clayton <bclayton@google.com>
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/ComputeProgram.cpp b/src/Pipeline/ComputeProgram.cpp
index 4ee8375..26d42d5 100644
--- a/src/Pipeline/ComputeProgram.cpp
+++ b/src/Pipeline/ComputeProgram.cpp
@@ -60,12 +60,19 @@
 
 void ComputeProgram::setWorkgroupBuiltins(Pointer<Byte> data, SpirvRoutine *routine, Int workgroupID[3])
 {
+	// TODO(b/146486064): Consider only assigning these to the SpirvRoutine iff
+	// they are ever going to be read.
+	routine->numWorkgroups = *Pointer<Int4>(data + OFFSET(Data, numWorkgroups));
+	routine->workgroupID = Insert(Insert(Insert(Int4(0), workgroupID[X], X), workgroupID[Y], Y), workgroupID[Z], Z);
+	routine->workgroupSize = *Pointer<Int4>(data + OFFSET(Data, workgroupSize));
+	routine->subgroupsPerWorkgroup = *Pointer<Int>(data + OFFSET(Data, subgroupsPerWorkgroup));
+	routine->invocationsPerSubgroup = *Pointer<Int>(data + OFFSET(Data, invocationsPerSubgroup));
+
 	routine->setInputBuiltin(shader, spv::BuiltInNumWorkgroups, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
-		auto numWorkgroups = *Pointer<Int4>(data + OFFSET(Data, numWorkgroups));
 		for(uint32_t component = 0; component < builtin.SizeInComponents; component++)
 		{
 			value[builtin.FirstComponent + component] =
-			    As<SIMD::Float>(SIMD::Int(Extract(numWorkgroups, component)));
+			    As<SIMD::Float>(SIMD::Int(Extract(routine->numWorkgroups, component)));
 		}
 	});
 
@@ -78,24 +85,21 @@
 	});
 
 	routine->setInputBuiltin(shader, spv::BuiltInWorkgroupSize, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
-		auto workgroupSize = *Pointer<Int4>(data + OFFSET(Data, workgroupSize));
 		for(uint32_t component = 0; component < builtin.SizeInComponents; component++)
 		{
 			value[builtin.FirstComponent + component] =
-			    As<SIMD::Float>(SIMD::Int(Extract(workgroupSize, component)));
+			    As<SIMD::Float>(SIMD::Int(Extract(routine->workgroupSize, component)));
 		}
 	});
 
 	routine->setInputBuiltin(shader, spv::BuiltInNumSubgroups, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
 		ASSERT(builtin.SizeInComponents == 1);
-		auto subgroupsPerWorkgroup = *Pointer<Int>(data + OFFSET(Data, subgroupsPerWorkgroup));
-		value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(subgroupsPerWorkgroup));
+		value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(routine->subgroupsPerWorkgroup));
 	});
 
 	routine->setInputBuiltin(shader, spv::BuiltInSubgroupSize, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
 		ASSERT(builtin.SizeInComponents == 1);
-		auto invocationsPerSubgroup = *Pointer<Int>(data + OFFSET(Data, invocationsPerSubgroup));
-		value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(invocationsPerSubgroup));
+		value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(routine->invocationsPerSubgroup));
 	});
 
 	routine->setImmutableInputBuiltins(shader);
@@ -120,6 +124,22 @@
 		localInvocationID[X] = idx;
 	}
 
+	Int4 wgID = Insert(Insert(Insert(SIMD::Int(0), workgroupID[X], X), workgroupID[Y], Y), workgroupID[Z], Z);
+	auto localBase = workgroupSize * wgID;
+	SIMD::Int globalInvocationID[3];
+	globalInvocationID[X] = SIMD::Int(Extract(localBase, X)) + localInvocationID[X];
+	globalInvocationID[Y] = SIMD::Int(Extract(localBase, Y)) + localInvocationID[Y];
+	globalInvocationID[Z] = SIMD::Int(Extract(localBase, Z)) + localInvocationID[Z];
+
+	routine->localInvocationIndex = localInvocationIndex;
+	routine->subgroupIndex = subgroupIndex;
+	routine->localInvocationID[X] = localInvocationID[X];
+	routine->localInvocationID[Y] = localInvocationID[Y];
+	routine->localInvocationID[Z] = localInvocationID[Z];
+	routine->globalInvocationID[X] = globalInvocationID[X];
+	routine->globalInvocationID[Y] = globalInvocationID[Y];
+	routine->globalInvocationID[Z] = globalInvocationID[Z];
+
 	routine->setInputBuiltin(shader, spv::BuiltInLocalInvocationIndex, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
 		ASSERT(builtin.SizeInComponents == 1);
 		value[builtin.FirstComponent] = As<SIMD::Float>(localInvocationIndex);
@@ -139,15 +159,10 @@
 	});
 
 	routine->setInputBuiltin(shader, spv::BuiltInGlobalInvocationId, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
-		SIMD::Int wgID = 0;
-		wgID = Insert(wgID, workgroupID[X], X);
-		wgID = Insert(wgID, workgroupID[Y], Y);
-		wgID = Insert(wgID, workgroupID[Z], Z);
-		auto localBase = workgroupSize * wgID;
 		for(uint32_t component = 0; component < builtin.SizeInComponents; component++)
 		{
-			auto globalInvocationID = SIMD::Int(Extract(localBase, component)) + localInvocationID[component];
-			value[builtin.FirstComponent + component] = As<SIMD::Float>(globalInvocationID);
+			value[builtin.FirstComponent + component] =
+			    As<SIMD::Float>(globalInvocationID[component]);
 		}
 	});
 }
diff --git a/src/Pipeline/PixelProgram.cpp b/src/Pipeline/PixelProgram.cpp
index 21296ed..0bfd0b0 100644
--- a/src/Pipeline/PixelProgram.cpp
+++ b/src/Pipeline/PixelProgram.cpp
@@ -60,17 +60,33 @@
 {
 	routine.setImmutableInputBuiltins(spirvShader);
 
+	// TODO(b/146486064): Consider only assigning these to the SpirvRoutine iff
+	// they are ever going to be read.
+	routine.fragCoord[0] = SIMD::Float(Float(x)) + SIMD::Float(0.5f, 1.5f, 0.5f, 1.5f);
+	routine.fragCoord[1] = SIMD::Float(Float(y)) + SIMD::Float(0.5f, 0.5f, 1.5f, 1.5f);
+	routine.fragCoord[2] = z[0];  // sample 0
+	routine.fragCoord[3] = w;
+	routine.pointCoord[0] = SIMD::Float(0.5f) +
+	                        SIMD::Float(Float(x) - (*Pointer<Float>(primitive + OFFSET(Primitive, pointCoordX))));
+	routine.pointCoord[1] = SIMD::Float(0.5f) +
+	                        SIMD::Float(Float(y) - (*Pointer<Float>(primitive + OFFSET(Primitive, pointCoordY))));
+	routine.invocationsPerSubgroup = SIMD::Width;
+	routine.helperInvocation = ~maskAny(cMask);
+	routine.windowSpacePosition[0] = x + SIMD::Int(0, 1, 0, 1);
+	routine.windowSpacePosition[1] = y + SIMD::Int(0, 0, 1, 1);
+	routine.viewID = *Pointer<Int>(data + OFFSET(DrawData, viewID));
+
 	routine.setInputBuiltin(spirvShader, spv::BuiltInViewIndex, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
 		assert(builtin.SizeInComponents == 1);
-		value[builtin.FirstComponent] = As<Float4>(Int4((*Pointer<Int>(data + OFFSET(DrawData, viewID)))));
+		value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(routine.viewID));
 	});
 
 	routine.setInputBuiltin(spirvShader, spv::BuiltInFragCoord, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
 		assert(builtin.SizeInComponents == 4);
-		value[builtin.FirstComponent + 0] = SIMD::Float(Float(x)) + SIMD::Float(0.5f, 1.5f, 0.5f, 1.5f);
-		value[builtin.FirstComponent + 1] = SIMD::Float(Float(y)) + SIMD::Float(0.5f, 0.5f, 1.5f, 1.5f);
-		value[builtin.FirstComponent + 2] = z[0];  // sample 0
-		value[builtin.FirstComponent + 3] = w;
+		value[builtin.FirstComponent + 0] = routine.fragCoord[0];
+		value[builtin.FirstComponent + 1] = routine.fragCoord[1];
+		value[builtin.FirstComponent + 2] = routine.fragCoord[2];
+		value[builtin.FirstComponent + 3] = routine.fragCoord[3];
 	});
 
 	routine.setInputBuiltin(spirvShader, spv::BuiltInPointCoord, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
@@ -88,12 +104,8 @@
 
 	routine.setInputBuiltin(spirvShader, spv::BuiltInHelperInvocation, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
 		assert(builtin.SizeInComponents == 1);
-		value[builtin.FirstComponent] = As<SIMD::Float>(~maskAny(cMask));
+		value[builtin.FirstComponent] = As<SIMD::Float>(routine.helperInvocation);
 	});
-
-	routine.windowSpacePosition[0] = x + SIMD::Int(0, 1, 0, 1);
-	routine.windowSpacePosition[1] = y + SIMD::Int(0, 0, 1, 1);
-	routine.viewID = *Pointer<Int>(data + OFFSET(DrawData, viewID));
 }
 
 void PixelProgram::applyShader(Int cMask[4], Int sMask[4], Int zMask[4])
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index db83240..f32cc63 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -1163,8 +1163,28 @@
 	Pointer<Byte> pushConstants;
 	Pointer<Byte> constants;
 	Int killMask = Int{ 0 };
+
+	// Shader invocation state.
+	// Not all of these variables are used for every type of shader, and some
+	// are only used when debugging. See b/146486064 for more information.
+	// Give careful consideration to the runtime performance loss before adding
+	// more state here.
 	SIMD::Int windowSpacePosition[2];
 	Int viewID;  // slice offset into input attachments for multiview, even if the shader doesn't use ViewIndex
+	Int instanceID;
+	SIMD::Int vertexIndex;
+	std::array<SIMD::Float, 4> fragCoord;
+	std::array<SIMD::Float, 4> pointCoord;
+	SIMD::Int helperInvocation;
+	Int4 numWorkgroups;
+	Int4 workgroupID;
+	Int4 workgroupSize;
+	Int subgroupsPerWorkgroup;
+	Int invocationsPerSubgroup;
+	Int subgroupIndex;
+	SIMD::Int localInvocationIndex;
+	std::array<SIMD::Int, 3> localInvocationID;
+	std::array<SIMD::Int, 3> globalInvocationID;
 
 	void createVariable(SpirvShader::Object::ID id, uint32_t size)
 	{
diff --git a/src/Pipeline/VertexProgram.cpp b/src/Pipeline/VertexProgram.cpp
index 615bcf3..4972ef2 100644
--- a/src/Pipeline/VertexProgram.cpp
+++ b/src/Pipeline/VertexProgram.cpp
@@ -34,15 +34,20 @@
 {
 	routine.setImmutableInputBuiltins(spirvShader);
 
+	// TODO(b/146486064): Consider only assigning these to the SpirvRoutine iff
+	// they are ever going to be read.
+	routine.viewID = *Pointer<Int>(data + OFFSET(DrawData, viewID));
+	routine.instanceID = *Pointer<Int>(data + OFFSET(DrawData, instanceID));
+
 	routine.setInputBuiltin(spirvShader, spv::BuiltInViewIndex, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
 		assert(builtin.SizeInComponents == 1);
-		value[builtin.FirstComponent] = As<Float4>(Int4((*Pointer<Int>(data + OFFSET(DrawData, viewID)))));
+		value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(routine.viewID));
 	});
 
 	routine.setInputBuiltin(spirvShader, spv::BuiltInInstanceIndex, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
 		// TODO: we could do better here; we know InstanceIndex is uniform across all lanes
 		assert(builtin.SizeInComponents == 1);
-		value[builtin.FirstComponent] = As<Float4>(Int4((*Pointer<Int>(data + OFFSET(DrawData, instanceID)))));
+		value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(routine.instanceID));
 	});
 
 	routine.setInputBuiltin(spirvShader, spv::BuiltInSubgroupSize, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
@@ -62,14 +67,15 @@
 
 void VertexProgram::program(Pointer<UInt> &batch, UInt &vertexCount)
 {
+	routine.vertexIndex = *Pointer<SIMD::Int>(As<Pointer<SIMD::Int>>(batch)) +
+	                      SIMD::Int(*Pointer<Int>(data + OFFSET(DrawData, baseVertex)));
+
 	auto it = spirvShader->inputBuiltins.find(spv::BuiltInVertexIndex);
 	if(it != spirvShader->inputBuiltins.end())
 	{
 		assert(it->second.SizeInComponents == 1);
-
 		routine.getVariable(it->second.Id)[it->second.FirstComponent] =
-		    As<Float4>(*Pointer<Int4>(As<Pointer<Int4>>(batch)) +
-		               Int4(*Pointer<Int>(data + OFFSET(DrawData, baseVertex))));
+		    As<SIMD::Float>(routine.vertexIndex);
 	}
 
 	auto activeLaneMask = SIMD::Int(0xFFFFFFFF);