bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node) { if (visit != PreVisit) return true; switch (node->getOp()) { case EOpCallInternalRawFunction: case EOpCallFunctionInAST: // User-defined function return values are not rounded. The calculations that produced // the value inside the function definition should have been rounded. break; case EOpConstruct: if (node->getBasicType() == EbtStruct) { break; } default: TIntermNode *parent = getParentNode(); if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) && !ParentConstructorTakesCareOfRounding(parent, node)) { TIntermNode *replacement = createRoundingFunctionCallNode(node); queueReplacement(replacement, OriginalNode::BECOMES_CHILD); } break; } return true; }
void EmulatePrecision::visitSymbol(TIntermSymbol *node) { TIntermNode *parent = getParentNode(); if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) && !ParentConstructorTakesCareOfRounding(parent, node) && !mDeclaringVariables && !isLValueRequiredHere()) { TIntermNode *replacement = createRoundingFunctionCallNode(node); queueReplacement(replacement, OriginalNode::BECOMES_CHILD); } }
bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) { bool visitChildren = true; TOperator op = node->getOp(); // RHS of initialize is not being declared. if (op == EOpInitialize && visit == InVisit) mDeclaringVariables = false; if ((op == EOpIndexDirectStruct) && visit == InVisit) visitChildren = false; if (visit != PreVisit) return visitChildren; const TType &type = node->getType(); bool roundFloat = canRoundFloat(type); if (roundFloat) { switch (op) { // Math operators that can result in a float may need to apply rounding to the return // value. Note that in the case of assignment, the rounding is applied to its return // value here, not the value being assigned. case EOpAssign: case EOpAdd: case EOpSub: case EOpMul: case EOpDiv: case EOpVectorTimesScalar: case EOpVectorTimesMatrix: case EOpMatrixTimesVector: case EOpMatrixTimesScalar: case EOpMatrixTimesMatrix: { TIntermNode *parent = getParentNode(); if (!ParentUsesResult(parent, node) || ParentConstructorTakesCareOfRounding(parent, node)) { break; } TIntermNode *replacement = createRoundingFunctionCallNode(node); queueReplacement(replacement, OriginalNode::BECOMES_CHILD); break; } // Compound assignment cases need to replace the operator with a function call. case EOpAddAssign: { mEmulateCompoundAdd.insert( TypePair(type.getBuiltInTypeNameString(), node->getRight()->getType().getBuiltInTypeNameString())); TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( node->getLeft(), node->getRight(), "add"); queueReplacement(replacement, OriginalNode::IS_DROPPED); break; } case EOpSubAssign: { mEmulateCompoundSub.insert( TypePair(type.getBuiltInTypeNameString(), node->getRight()->getType().getBuiltInTypeNameString())); TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( node->getLeft(), node->getRight(), "sub"); queueReplacement(replacement, OriginalNode::IS_DROPPED); break; } case EOpMulAssign: case EOpVectorTimesMatrixAssign: case EOpVectorTimesScalarAssign: case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: { mEmulateCompoundMul.insert( TypePair(type.getBuiltInTypeNameString(), node->getRight()->getType().getBuiltInTypeNameString())); TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( node->getLeft(), node->getRight(), "mul"); queueReplacement(replacement, OriginalNode::IS_DROPPED); break; } case EOpDivAssign: { mEmulateCompoundDiv.insert( TypePair(type.getBuiltInTypeNameString(), node->getRight()->getType().getBuiltInTypeNameString())); TIntermNode *replacement = createCompoundAssignmentFunctionCallNode( node->getLeft(), node->getRight(), "div"); queueReplacement(replacement, OriginalNode::IS_DROPPED); break; } default: // The rest of the binary operations should not need precision emulation. break; } } return visitChildren; }