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; }
bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) { bool visitChildren = true; if (node->isAssignment()) { if (visit == PreVisit) mInLValue = true; else if (visit == InVisit) mInLValue = false; } TOperator op = node->getOp(); // RHS of initialize is not being declared. if (op == EOpInitialize && visit == InVisit) mDeclaringVariables = false; if ((op == EOpIndexDirectStruct || op == EOpVectorSwizzle) && 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)) { break; } TIntermNode *replacement = createRoundingFunctionCallNode(node); mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); break; } // Compound assignment cases need to replace the operator with a function call. case EOpAddAssign: { mEmulateCompoundAdd.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); TIntermNode *parent = getParentNode(); TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "add"); mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); break; } case EOpSubAssign: { mEmulateCompoundSub.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); TIntermNode *parent = getParentNode(); TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "sub"); mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); break; } case EOpMulAssign: case EOpVectorTimesMatrixAssign: case EOpVectorTimesScalarAssign: case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: { mEmulateCompoundMul.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); TIntermNode *parent = getParentNode(); TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "mul"); mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); break; } case EOpDivAssign: { mEmulateCompoundDiv.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); TIntermNode *parent = getParentNode(); TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "div"); mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); break; } default: // The rest of the binary operations should not need precision emulation. break; } } return visitChildren; }