Fragment output location fix

The previous fix wasn't handling the case where the same fragment
output variable would go through declareFragmentOutput() multiple
times, so this cl fixes it.

Fixes all dEQP-GLES3.functional.shaders.random failures.
Still fixes original WebGL2 conformance tests failures in:
all/deqp/functional/gles3/fragmentoutput

Change-Id: Ia9c4f5ed5c444ab0c020cac8be511fcaad23c55d
Reviewed-on: https://swiftshader-review.googlesource.com/16928
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/compiler/OutputASM.cpp b/src/OpenGL/compiler/OutputASM.cpp
index f61dce1..81cac70 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -3180,29 +3180,55 @@
 	void OutputASM::declareFragmentOutput(TIntermTyped *fragmentOutput)
 	{
 		int requestedLocation = fragmentOutput->getType().getLayoutQualifier().location;
-		if((requestedLocation >= 0) && (requestedLocation < sw::RENDERTARGETS))
+		int registerCount = fragmentOutput->totalRegisterCount();
+		if(requestedLocation < 0)
 		{
-			if(fragmentOutputs.size() <= (size_t)requestedLocation)
-			{
-				while(fragmentOutputs.size() < (size_t)requestedLocation)
-				{
-					fragmentOutputs.push_back(nullptr);
-				}
-				fragmentOutputs.push_back(fragmentOutput);
-			}
-			else if(!fragmentOutputs[requestedLocation])
-			{
-				fragmentOutputs[requestedLocation] = fragmentOutput;
-			}
-			else
-			{
-				mContext.error(fragmentOutput->getLine(), "Fragment output location aliasing", "fragment shader");
-			}
+			mContext.error(fragmentOutput->getLine(), "Invalid fragment output location", "fragment shader");
 		}
-		else if(requestedLocation >= sw::RENDERTARGETS)
+		else if((requestedLocation + registerCount) > sw::RENDERTARGETS)
 		{
 			mContext.error(fragmentOutput->getLine(), "Fragment output location larger or equal to MAX_DRAW_BUFFERS", "fragment shader");
 		}
+		else
+		{
+			int currentIndex = lookup(fragmentOutputs, fragmentOutput);
+			if(requestedLocation != currentIndex)
+			{
+				if(currentIndex != -1)
+				{
+					mContext.error(fragmentOutput->getLine(), "Multiple locations for fragment output", "fragment shader");
+				}
+				else
+				{
+					if(fragmentOutputs.size() <= (size_t)requestedLocation)
+					{
+						while(fragmentOutputs.size() < (size_t)requestedLocation)
+						{
+							fragmentOutputs.push_back(nullptr);
+						}
+						for(int i = 0; i < registerCount; i++)
+						{
+							fragmentOutputs.push_back(fragmentOutput);
+						}
+					}
+					else
+					{
+						for(int i = 0; i < registerCount; i++)
+						{
+							if(!fragmentOutputs[requestedLocation + i])
+							{
+								fragmentOutputs[requestedLocation + i] = fragmentOutput;
+							}
+							else
+							{
+								mContext.error(fragmentOutput->getLine(), "Fragment output location aliasing", "fragment shader");
+								return;
+							}
+						}
+					}
+				}
+			}
+		}
 	}
 
 	int OutputASM::uniformRegister(TIntermTyped *uniform)