Ejemplo n.º 1
0
bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node)
{
    switch (node->getOp())
    {
      case EOpNegative:
      case EOpVectorLogicalNot:
      case EOpLogicalNot:
        break;
      case EOpPostIncrement:
      case EOpPostDecrement:
      case EOpPreIncrement:
      case EOpPreDecrement:
        if (visit == PreVisit)
            mInLValue = true;
        else if (visit == PostVisit)
            mInLValue = false;
        break;
      default:
        if (canRoundFloat(node->getType()) && visit == PreVisit)
        {
            TIntermNode *parent = getParentNode();
            TIntermNode *replacement = createRoundingFunctionCallNode(node);
            mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
        }
        break;
    }

    return true;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
void EmulatePrecision::visitSymbol(TIntermSymbol *node)
{
    if (canRoundFloat(node->getType()) &&
        !mDeclaringVariables && !mInLValue && !mInFunctionCallOutParameter)
    {
        TIntermNode *parent = getParentNode();
        TIntermNode *replacement = createRoundingFunctionCallNode(node);
        mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
    }
}
Ejemplo n.º 4
0
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);
    }
}
Ejemplo n.º 5
0
bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node)
{
    switch (node->getOp())
    {
        case EOpNegative:
        case EOpLogicalNot:
        case EOpPostIncrement:
        case EOpPostDecrement:
        case EOpPreIncrement:
        case EOpPreDecrement:
        case EOpLogicalNotComponentWise:
            break;
        default:
            if (canRoundFloat(node->getType()) && visit == PreVisit)
            {
                TIntermNode *replacement = createRoundingFunctionCallNode(node);
                queueReplacement(replacement, OriginalNode::BECOMES_CHILD);
            }
            break;
    }

    return true;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
{
    bool visitChildren = true;
    switch (node->getOp())
    {
      case EOpSequence:
      case EOpConstructStruct:
        // No special handling
        break;
      case EOpFunction:
        if (visit == PreVisit)
        {
            const TIntermSequence &sequence = *(node->getSequence());
            TIntermSequence::const_iterator seqIter = sequence.begin();
            TIntermAggregate *params = (*seqIter)->getAsAggregate();
            ASSERT(params != NULL);
            ASSERT(params->getOp() == EOpParameters);
            mFunctionMap[node->getName()] = params->getSequence();
        }
        break;
      case EOpPrototype:
        if (visit == PreVisit)
            mFunctionMap[node->getName()] = node->getSequence();
        visitChildren = false;
        break;
      case EOpParameters:
        visitChildren = false;
        break;
      case EOpInvariantDeclaration:
        visitChildren = false;
        break;
      case EOpDeclaration:
        // Variable declaration.
        if (visit == PreVisit)
        {
            mDeclaringVariables = true;
        }
        else if (visit == InVisit)
        {
            mDeclaringVariables = true;
        }
        else
        {
            mDeclaringVariables = false;
        }
        break;
      case EOpFunctionCall:
      {
        // Function call.
        bool inFunctionMap = (mFunctionMap.find(node->getName()) != mFunctionMap.end());
        if (visit == PreVisit)
        {
            // User-defined function return values are not rounded, this relies on that
            // calculations producing the value were rounded.
            TIntermNode *parent = getParentNode();
            if (canRoundFloat(node->getType()) && !inFunctionMap && parentUsesResult(parent, node))
            {
                TIntermNode *replacement = createRoundingFunctionCallNode(node);
                mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
            }

            if (inFunctionMap)
            {
                mSeqIterStack.push_back(mFunctionMap[node->getName()]->begin());
                if (mSeqIterStack.back() != mFunctionMap[node->getName()]->end())
                {
                    TQualifier qualifier = (*mSeqIterStack.back())->getAsTyped()->getQualifier();
                    mInFunctionCallOutParameter = (qualifier == EvqOut || qualifier == EvqInOut);
                }
            }
            else
            {
                // The function is not user-defined - it is likely built-in texture function.
                // Assume that those do not have out parameters.
                mInFunctionCallOutParameter = false;
            }
        }
        else if (visit == InVisit)
        {
            if (inFunctionMap)
            {
                ++mSeqIterStack.back();
                TQualifier qualifier = (*mSeqIterStack.back())->getAsTyped()->getQualifier();
                mInFunctionCallOutParameter = (qualifier == EvqOut || qualifier == EvqInOut);
            }
        }
        else
        {
            if (inFunctionMap)
            {
                mSeqIterStack.pop_back();
                mInFunctionCallOutParameter = false;
            }
        }
        break;
      }
      default:
        TIntermNode *parent = getParentNode();
        if (canRoundFloat(node->getType()) && visit == PreVisit && parentUsesResult(parent, node))
        {
            TIntermNode *replacement = createRoundingFunctionCallNode(node);
            mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true));
        }
        break;
    }
    return visitChildren;
}
Ejemplo n.º 8
0
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;
}