Uniform buffer uniform unpacking utility function

When data is packed into uniform blocks, some data isn't formatted in
a way that fits how data is usually represented, which is the case
for booleans and row major matrices. In these 2 cases, the variables
are unpacked into temporaries before being used. Booleans can be any
integer value and any non-zero value represents "true", so the value
in the uniform buffer has to go through an int to bool conversion
before being used. For row major matrices, a given register of that
matrix has to be transposed into a temporary before being used.

Change-Id: I0e001ceff2ce9be9a3570171e184586afc48c02d
Reviewed-on: https://swiftshader-review.googlesource.com/5040
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/compiler/OutputASM.cpp b/src/OpenGL/compiler/OutputASM.cpp
index 15bb374..9ca21ad 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -2064,6 +2064,66 @@
 		if(argument)

 		{

 			TIntermTyped *arg = argument->getAsTyped();

+			Temporary unpackedUniform(this);

+

+			const TType& srcType = arg->getType();

+			TInterfaceBlock* srcBlock = srcType.getInterfaceBlock();

+			if(srcBlock && (srcType.getQualifier() == EvqUniform))

+			{

+				const ArgumentInfo argumentInfo = getArgumentInfo(arg, index);

+				const TType &memberType = argumentInfo.typedMemberInfo.type;

+

+				if(memberType.getBasicType() == EbtBool)

+				{

+					int arraySize = (memberType.isArray() ? memberType.getArraySize() : 1);

+					ASSERT(argumentInfo.clampedIndex < arraySize);

+

+					// Convert the packed bool, which is currently an int, to a true bool

+					Instruction *instruction = new Instruction(sw::Shader::OPCODE_I2B);

+					instruction->dst.type = sw::Shader::PARAMETER_TEMP;

+					instruction->dst.index = registerIndex(&unpackedUniform);

+					instruction->src[0].type = sw::Shader::PARAMETER_CONST;

+					instruction->src[0].bufferIndex = argumentInfo.bufferIndex;

+					instruction->src[0].index = argumentInfo.typedMemberInfo.offset + argumentInfo.clampedIndex * argumentInfo.typedMemberInfo.arrayStride;

+

+					shader->append(instruction);

+

+					arg = &unpackedUniform;

+					index = 0;

+				}

+				else if((srcBlock->matrixPacking() == EmpRowMajor) && memberType.isMatrix())

+				{

+					int numCols = memberType.getNominalSize();

+					int numRows = memberType.getSecondarySize();

+					int arraySize = (memberType.isArray() ? memberType.getArraySize() : 1);

+

+					ASSERT(argumentInfo.clampedIndex < (numCols * arraySize));

+

+					unsigned int dstIndex = registerIndex(&unpackedUniform);

+					unsigned int srcSwizzle = (argumentInfo.clampedIndex % numCols) * 0x55;

+					int arrayIndex = argumentInfo.clampedIndex / numCols;

+					int matrixStartOffset = argumentInfo.typedMemberInfo.offset + arrayIndex * argumentInfo.typedMemberInfo.arrayStride;

+

+					for(int j = 0; j < numRows; ++j)

+					{

+						// Transpose the row major matrix

+						Instruction *instruction = new Instruction(sw::Shader::OPCODE_MOV);

+						instruction->dst.type = sw::Shader::PARAMETER_TEMP;

+						instruction->dst.index = dstIndex;

+						instruction->dst.mask = 1 << j;

+						instruction->src[0].type = sw::Shader::PARAMETER_CONST;

+						instruction->src[0].bufferIndex = argumentInfo.bufferIndex;

+						instruction->src[0].index = matrixStartOffset + j * argumentInfo.typedMemberInfo.matrixStride;

+						instruction->src[0].swizzle = srcSwizzle;

+

+						shader->append(instruction);

+					}

+

+					arg = &unpackedUniform;

+					index = 0;

+				}

+			}

+

 			const ArgumentInfo argumentInfo = getArgumentInfo(arg, index);

 			const TType &type = argumentInfo.typedMemberInfo.type;