Multiple draw buffers implementation

Implemented the missing pieces for multiple draw buffers support:
- Fixed Context::getScissoredImage() to use the drawbuffer
  parameter properly
- Enabled setting multiple render targets
- Added dynamic indexing of gl_FragData using a new dynOut flag
  to figure out which channels are being written to.

Change-Id: Id3d95c46a980a698f71e99f7781cc6287e880e9d
Reviewed-on: https://swiftshader-review.googlesource.com/4220
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/Shader/PixelProgram.cpp b/src/Shader/PixelProgram.cpp
index 80fe7d6..46ca81c 100644
--- a/src/Shader/PixelProgram.cpp
+++ b/src/Shader/PixelProgram.cpp
@@ -72,7 +72,13 @@
 			r.enableLeave = Int4(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
 		}
 
-		bool out[4][4] = { false };
+		for(int i = 0; i < RENDERTARGETS; i++)
+		{
+			if(state.targetFormat[i] != FORMAT_NULL)
+			{
+				r.oC[i] = Vector4f(0.0f, 0.0f, 0.0f, 0.0f);
+			}
+		}
 
 		// Create all call site return blocks up front
 		for(size_t i = 0; i < shader->getLength(); i++)
@@ -362,11 +368,22 @@
 						}
 						break;
 					case Shader::PARAMETER_COLOROUT:
-						ASSERT(dst.rel.type == Shader::PARAMETER_VOID);
-						if(dst.x) pDst.x = r.oC[dst.index].x;
-						if(dst.y) pDst.y = r.oC[dst.index].y;
-						if(dst.z) pDst.z = r.oC[dst.index].z;
-						if(dst.w) pDst.w = r.oC[dst.index].w;
+						if(dst.rel.type == Shader::PARAMETER_VOID)
+						{
+							if(dst.x) pDst.x = r.oC[dst.index].x;
+							if(dst.y) pDst.y = r.oC[dst.index].y;
+							if(dst.z) pDst.z = r.oC[dst.index].z;
+							if(dst.w) pDst.w = r.oC[dst.index].w;
+						}
+						else
+						{
+							Int a = relativeAddress(r, dst) + dst.index;
+
+							if(dst.x) pDst.x = r.oC[a].x;
+							if(dst.y) pDst.y = r.oC[a].y;
+							if(dst.z) pDst.z = r.oC[a].z;
+							if(dst.w) pDst.w = r.oC[a].w;
+						}
 						break;
 					case Shader::PARAMETER_PREDICATE:
 						if(dst.x) pDst.x = r.p0.x;
@@ -445,11 +462,22 @@
 					}
 					break;
 				case Shader::PARAMETER_COLOROUT:
-					ASSERT(dst.rel.type == Shader::PARAMETER_VOID);
-					if(dst.x) { r.oC[dst.index].x = d.x; out[dst.index][0] = true; }
-					if(dst.y) { r.oC[dst.index].y = d.y; out[dst.index][1] = true; }
-					if(dst.z) { r.oC[dst.index].z = d.z; out[dst.index][2] = true; }
-					if(dst.w) { r.oC[dst.index].w = d.w; out[dst.index][3] = true; }
+					if(dst.rel.type == Shader::PARAMETER_VOID)
+					{
+						if(dst.x) { r.oC[dst.index].x = d.x; }
+						if(dst.y) { r.oC[dst.index].y = d.y; }
+						if(dst.z) { r.oC[dst.index].z = d.z; }
+						if(dst.w) { r.oC[dst.index].w = d.w; }
+					}
+					else
+					{
+						Int a = relativeAddress(r, dst) + dst.index;
+
+						if(dst.x) { r.oC[a].x = d.x; }
+						if(dst.y) { r.oC[a].y = d.y; }
+						if(dst.z) { r.oC[a].z = d.z; }
+						if(dst.w) { r.oC[a].w = d.w; }
+					}
 					break;
 				case Shader::PARAMETER_PREDICATE:
 					if(dst.x) r.p0.x = d.x;
@@ -471,15 +499,9 @@
 			Nucleus::setInsertBlock(returnBlock);
 		}
 
-		for(int i = 0; i < 4; i++)
+		for(int i = 0; i < RENDERTARGETS; i++)
 		{
-			if(state.targetFormat[i] != FORMAT_NULL)
-			{
-				if(!out[i][0]) r.oC[i].x = Float4(0.0f);
-				if(!out[i][1]) r.oC[i].y = Float4(0.0f);
-				if(!out[i][2]) r.oC[i].z = Float4(0.0f);
-				if(!out[i][3]) r.oC[i].w = Float4(0.0f);
-			}
+			r.c[i] = r.oC[i];
 		}
 	}
 

@@ -487,7 +509,7 @@
 	{

 		Registers& r = *static_cast<Registers*>(&rBase);

 

-		clampColor(r.oC);

+		clampColor(r.c);
 

 		if(!state.alphaTestActive())
 		{
@@ -498,7 +520,7 @@
 
 		if(state.transparencyAntialiasing == TRANSPARENCY_NONE)
 		{
-			Short4 alpha = RoundShort4(r.oC[0].w * Float4(0x1000));
+			Short4 alpha = RoundShort4(r.c[0].w * Float4(0x1000));
 
 			PixelRoutine::alphaTest(r, aMask, alpha);
 
@@ -509,7 +531,7 @@
 		}
 		else if(state.transparencyAntialiasing == TRANSPARENCY_ALPHA_TO_COVERAGE)
 		{
-			alphaToCoverage(r, cMask, r.oC[0].w);
+			alphaToCoverage(r, cMask, r.c[0].w);
 		}
 		else ASSERT(false);
 
@@ -527,23 +549,23 @@
 	{

 		Registers& r = *static_cast<Registers*>(&rBase);

 

-		for(int index = 0; index < 4; index++)
+		for(int index = 0; index < RENDERTARGETS; index++)
 		{
 			if(!state.colorWriteActive(index))
 			{
 				continue;
-			}
+			}

 
 			if(!postBlendSRGB && state.writeSRGB)
 			{
-				r.oC[index].x = linearToSRGB(r.oC[index].x);
-				r.oC[index].y = linearToSRGB(r.oC[index].y);
-				r.oC[index].z = linearToSRGB(r.oC[index].z);
+				r.c[index].x = linearToSRGB(r.c[index].x);
+				r.c[index].y = linearToSRGB(r.c[index].y);
+				r.c[index].z = linearToSRGB(r.c[index].z);
 			}
 
 			if(index == 0)
 			{
-				fogBlend(r, r.oC[index], fog);
+				fogBlend(r, r.c[index], fog);
 			}
 
 			switch(state.targetFormat[index])
@@ -561,10 +583,10 @@
 					Pointer<Byte> buffer = cBuffer[index] + q * *Pointer<Int>(r.data + OFFSET(DrawData, colorSliceB[index]));
 					Vector4s color;
 
-					color.x = convertFixed16(r.oC[index].x, false);
-					color.y = convertFixed16(r.oC[index].y, false);
-					color.z = convertFixed16(r.oC[index].z, false);
-					color.w = convertFixed16(r.oC[index].w, false);
+					color.x = convertFixed16(r.c[index].x, false);
+					color.y = convertFixed16(r.c[index].y, false);
+					color.z = convertFixed16(r.c[index].z, false);
+					color.w = convertFixed16(r.c[index].w, false);
 
 					if(state.multiSampleMask & (1 << q))
 					{
@@ -580,7 +602,7 @@
 				for(unsigned int q = 0; q < state.multiSample; q++)
 				{
 					Pointer<Byte> buffer = cBuffer[index] + q * *Pointer<Int>(r.data + OFFSET(DrawData, colorSliceB[index]));
-					Vector4f color = r.oC[index];
+					Vector4f color = r.c[index];
 
 					if(state.multiSampleMask & (1 << q))
 					{
@@ -593,7 +615,7 @@
 				ASSERT(false);
 			}
 		}
-	}

+	}
 
 	void PixelProgram::sampleTexture(Registers &r, Vector4f &c, const Src &sampler, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Vector4f &dsx, Vector4f &dsy, bool project, bool bias, bool gradients, bool lodProvided)
 	{
@@ -647,9 +669,9 @@
 #endif
 	}
 
-	void PixelProgram::clampColor(Vector4f oC[4])
+	void PixelProgram::clampColor(Vector4f oC[RENDERTARGETS])
 	{
-		for(int index = 0; index < 4; index++)
+		for(int index = 0; index < RENDERTARGETS; index++)
 		{
 			if(!state.colorWriteActive(index) && !(index == 0 && state.alphaTestActive()))
 			{
@@ -779,7 +801,16 @@
 		case Shader::PARAMETER_CONSTBOOL:   return reg; // Dummy
 		case Shader::PARAMETER_LOOP:        return reg; // Dummy
 		case Shader::PARAMETER_COLOROUT:
-			reg = r.oC[i];
+			if(src.rel.type == Shader::PARAMETER_VOID)   // Not relative
+			{
+				reg = r.oC[i];
+			}
+			else
+			{
+				Int a = relativeAddress(r, src);
+
+				reg = r.oC[i + a];
+			}
 			break;
 		case Shader::PARAMETER_DEPTHOUT:
 			reg.x = r.oDepth;