Fix indexing of samplers in structures.
Change-Id: I0bde678865902d549d4260bf8f6c1a368a46f4d4
Reviewed-on: https://swiftshader-review.googlesource.com/5191
Tested-by: Nicolas Capens <capn@google.com>
Reviewed-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 cc4bd45..88a8780 100644
--- a/src/OpenGL/compiler/OutputASM.cpp
+++ b/src/OpenGL/compiler/OutputASM.cpp
@@ -495,6 +495,11 @@
const TType &rightType = right->getType();
const TType &resultType = node->getType();
+ if(isSamplerRegister(result))
+ {
+ return false; // Don't traverse, the register index is determined statically
+ }
+
switch(node->getOp())
{
case EOpAssign:
@@ -1758,21 +1763,6 @@
return true;
}
- bool OutputASM::isSamplerRegister(TIntermTyped *operand)
- {
- return operand && isSamplerRegister(operand->getType());
- }
-
- bool OutputASM::isSamplerRegister(const TType &type)
- {
- // A sampler register's qualifiers can be:
- // - EvqUniform: The sampler uniform is used as is in the code (default case).
- // - EvqTemporary: The sampler is indexed. It's still a sampler register.
- // - EvqIn (and other similar types): The sampler has been passed as a function argument. At this point,
- // the sampler has been copied and is no longer a sampler register.
- return IsSampler(type.getBasicType()) && (type.getQualifier() == EvqUniform || type.getQualifier() == EvqTemporary);
- }
-
Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, TIntermNode *src0, TIntermNode *src1, TIntermNode *src2, TIntermNode *src3, TIntermNode *src4)
{
return emit(op, dst, 0, src0, 0, src1, 0, src2, 0, src3, 0, src4, 0);
@@ -1781,11 +1771,6 @@
Instruction *OutputASM::emit(sw::Shader::Opcode op, TIntermTyped *dst, int dstIndex, TIntermNode *src0, int index0, TIntermNode *src1, int index1,
TIntermNode *src2, int index2, TIntermNode *src3, int index3, TIntermNode *src4, int index4)
{
- if(isSamplerRegister(dst))
- {
- op = sw::Shader::OPCODE_NULL; // Can't assign to a sampler, but this is hit when indexing sampler arrays
- }
-
Instruction *instruction = new Instruction(op);
if(dst)
@@ -2172,39 +2157,7 @@
{
parameter.index = registerIndex(arg) + argumentInfo.clampedIndex;
- if(isSamplerRegister(arg))
- {
- TIntermBinary *binary = argument->getAsBinaryNode();
-
- if(binary)
- {
- TIntermTyped *left = binary->getLeft();
- TIntermTyped *right = binary->getRight();
-
- switch(binary->getOp())
- {
- case EOpIndexDirect:
- parameter.index += right->getAsConstantUnion()->getIConst(0);
- break;
- case EOpIndexIndirect:
- if(left->getArraySize() > 1)
- {
- parameter.rel.type = registerType(binary->getRight());
- parameter.rel.index = registerIndex(binary->getRight());
- parameter.rel.scale = 1;
- parameter.rel.deterministic = true;
- }
- break;
- case EOpIndexDirectStruct:
- case EOpIndexDirectInterfaceBlock:
- parameter.index += right->getAsConstantUnion()->getIConst(0);
- break;
- default:
- UNREACHABLE(binary->getOp());
- }
- }
- }
- else if(parameter.bufferIndex != -1)
+ if(parameter.bufferIndex != -1)
{
int stride = (argumentInfo.typedMemberInfo.matrixStride > 0) ? argumentInfo.typedMemberInfo.matrixStride : argumentInfo.typedMemberInfo.arrayStride;
parameter.index = argumentInfo.typedMemberInfo.offset + argumentInfo.clampedIndex * stride;
@@ -2884,30 +2837,57 @@
int OutputASM::samplerRegister(TIntermTyped *sampler)
{
- ASSERT(IsSampler(sampler->getType().getBasicType()));
+ const TType &type = sampler->getType();
+ ASSERT(IsSampler(type.getBasicType()) || type.isStruct()); // Structures can contain samplers
+
TIntermSymbol *symbol = sampler->getAsSymbolNode();
TIntermBinary *binary = sampler->getAsBinaryNode();
- if(symbol)
+ if(symbol && type.getQualifier() == EvqUniform)
{
return samplerRegister(symbol);
}
else if(binary)
{
- ASSERT(binary->getOp() == EOpIndexDirect || binary->getOp() == EOpIndexIndirect ||
- binary->getOp() == EOpIndexDirectStruct || binary->getOp() == EOpIndexDirectInterfaceBlock);
+ TIntermTyped *left = binary->getLeft();
+ TIntermTyped *right = binary->getRight();
+ const TType &leftType = left->getType();
+ int index = right->getAsConstantUnion() ? right->getAsConstantUnion()->getIConst(0) : 0;
- return samplerRegister(binary->getLeft()); // Index added later
+ switch(binary->getOp())
+ {
+ case EOpIndexDirect:
+ ASSERT(left->isArray());
+ return samplerRegister(left) + index * leftType.elementRegisterCount();
+ case EOpIndexDirectStruct:
+ {
+ ASSERT(leftType.isStruct());
+ const TFieldList &fields = leftType.getStruct()->fields();
+ int fieldOffset = 0;
+
+ for(int i = 0; i < index; i++)
+ {
+ fieldOffset += fields[i]->type()->totalRegisterCount();
+ }
+
+ return samplerRegister(left) + fieldOffset;
+ }
+ case EOpIndexDirectInterfaceBlock: // Interface blocks can't contain samplers
+ case EOpIndexIndirect: // Indirect indexing produces a temporary, not a sampler register
+ default:
+ UNREACHABLE(binary->getOp());
+ return 0;
+ }
}
- else UNREACHABLE(0);
- return 0;
+ UNREACHABLE(0);
+ return 0; // Not a sampler register
}
int OutputASM::samplerRegister(TIntermSymbol *sampler)
{
const TType &type = sampler->getType();
- ASSERT(IsSampler(type.getBasicType()) || type.getStruct()); // Structures can contain samplers
+ ASSERT(IsSampler(type.getBasicType()) || type.isStruct()); // Structures can contain samplers
int index = lookup(samplers, sampler);
@@ -2925,6 +2905,11 @@
return index;
}
+ bool OutputASM::isSamplerRegister(TIntermTyped *operand)
+ {
+ return operand && IsSampler(operand->getBasicType()) && samplerRegister(operand) >= 0;
+ }
+
int OutputASM::lookup(VariableArray &list, TIntermTyped *variable)
{
for(unsigned int i = 0; i < list.size(); i++)
@@ -3110,7 +3095,7 @@
int fieldRegisterIndex = encoder ? shaderObject->activeUniformBlocks[blockId].registerIndex + BlockLayoutEncoder::getBlockRegister(blockInfo) : registerIndex;
activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(),
fieldRegisterIndex, blockId, blockInfo));
- if(isSamplerRegister(type))
+ if(IsSampler(type.getBasicType()))
{
for(int i = 0; i < type.totalRegisterCount(); i++)
{
diff --git a/src/OpenGL/compiler/OutputASM.h b/src/OpenGL/compiler/OutputASM.h
index 2329cf5..854c262 100644
--- a/src/OpenGL/compiler/OutputASM.h
+++ b/src/OpenGL/compiler/OutputASM.h
@@ -286,6 +286,7 @@
int fragmentOutputRegister(TIntermTyped *fragmentOutput);
int samplerRegister(TIntermTyped *sampler);
int samplerRegister(TIntermSymbol *sampler);
+ bool isSamplerRegister(TIntermTyped *operand);
typedef std::vector<TIntermTyped*> VariableArray;
@@ -302,8 +303,6 @@
static int dim(TIntermNode *v);
static int dim2(TIntermNode *m);
static unsigned int loopCount(TIntermLoop *node);
- static bool isSamplerRegister(TIntermTyped *operand);
- static bool isSamplerRegister(const TType &type);
Shader *const shaderObject;
sw::Shader *shader;