Edit

kc3-lang/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2017-01-02 17:34:40
    Hash : d68924e5
    Message : Use GetOperatorString when writing GLSL unary built-in calls GetOperatorString is now used when writing GLSL for built-in calls that fall under TIntermUnary. Component-wise not TOperator enum is renamed for consistency. This also cleans up some unnecessary creation of string objects when writing built-in functions. BUG=angleproject:1682 TEST=angle_unittests, angle_end2end_tests, WebGL conformance tests Change-Id: I89b2ef222bf5af479d4977417f320789b58ace85 Reviewed-on: https://chromium-review.googlesource.com/424552 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/BuiltInFunctionEmulator.cpp
  • //
    // Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    #include "angle_gl.h"
    #include "compiler/translator/BuiltInFunctionEmulator.h"
    #include "compiler/translator/SymbolTable.h"
    #include "compiler/translator/Cache.h"
    
    namespace sh
    {
    
    class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
    {
      public:
        BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
            : TIntermTraverser(true, false, false), mEmulator(emulator)
        {
        }
    
        bool visitUnary(Visit visit, TIntermUnary *node) override
        {
            if (visit == PreVisit)
            {
                bool needToEmulate =
                    mEmulator.SetFunctionCalled(node->getOp(), node->getOperand()->getType());
                if (needToEmulate)
                    node->setUseEmulatedFunction();
            }
            return true;
        }
    
        bool visitAggregate(Visit visit, TIntermAggregate *node) override
        {
            if (visit == PreVisit)
            {
                // Here we handle all the built-in functions instead of the ones we
                // currently identified as problematic.
                switch (node->getOp())
                {
                    case EOpEqualComponentWise:
                    case EOpNotEqualComponentWise:
                    case EOpLessThanComponentWise:
                    case EOpGreaterThanComponentWise:
                    case EOpLessThanEqualComponentWise:
                    case EOpGreaterThanEqualComponentWise:
                    case EOpMod:
                    case EOpPow:
                    case EOpAtan:
                    case EOpMin:
                    case EOpMax:
                    case EOpClamp:
                    case EOpMix:
                    case EOpStep:
                    case EOpSmoothStep:
                    case EOpDistance:
                    case EOpDot:
                    case EOpCross:
                    case EOpFaceForward:
                    case EOpReflect:
                    case EOpRefract:
                    case EOpMulMatrixComponentWise:
                    case EOpOuterProduct:
                        break;
                    default:
                        return true;
                }
                const TIntermSequence &sequence = *(node->getSequence());
                bool needToEmulate              = false;
                // Right now we only handle built-in functions with two or three parameters.
                if (sequence.size() == 2)
                {
                    TIntermTyped *param1 = sequence[0]->getAsTyped();
                    TIntermTyped *param2 = sequence[1]->getAsTyped();
                    if (!param1 || !param2)
                        return true;
                    needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), param1->getType(),
                                                                param2->getType());
                }
                else if (sequence.size() == 3)
                {
                    TIntermTyped *param1 = sequence[0]->getAsTyped();
                    TIntermTyped *param2 = sequence[1]->getAsTyped();
                    TIntermTyped *param3 = sequence[2]->getAsTyped();
                    if (!param1 || !param2 || !param3)
                        return true;
                    needToEmulate = mEmulator.SetFunctionCalled(node->getOp(), param1->getType(),
                                                                param2->getType(), param3->getType());
                }
                else
                {
                    return true;
                }
    
                if (needToEmulate)
                    node->setUseEmulatedFunction();
            }
            return true;
        }
    
      private:
        BuiltInFunctionEmulator &mEmulator;
    };
    
    BuiltInFunctionEmulator::BuiltInFunctionEmulator()
    {
    }
    
    BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction(
        TOperator op,
        const TType *param,
        const char *emulatedFunctionDefinition)
    {
        FunctionId id(op, param);
        mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
        return id;
    }
    
    BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction(
        TOperator op,
        const TType *param1,
        const TType *param2,
        const char *emulatedFunctionDefinition)
    {
        FunctionId id(op, param1, param2);
        mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
        return id;
    }
    
    BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
        FunctionId dependency,
        TOperator op,
        const TType *param1,
        const TType *param2,
        const char *emulatedFunctionDefinition)
    {
        FunctionId id(op, param1, param2);
        mEmulatedFunctions[id]    = std::string(emulatedFunctionDefinition);
        mFunctionDependencies[id] = dependency;
        return id;
    }
    
    BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::addEmulatedFunction(
        TOperator op,
        const TType *param1,
        const TType *param2,
        const TType *param3,
        const char *emulatedFunctionDefinition)
    {
        FunctionId id(op, param1, param2, param3);
        mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
        return id;
    }
    
    bool BuiltInFunctionEmulator::IsOutputEmpty() const
    {
        return (mFunctions.size() == 0);
    }
    
    void BuiltInFunctionEmulator::OutputEmulatedFunctions(TInfoSinkBase &out) const
    {
        for (size_t i = 0; i < mFunctions.size(); ++i)
        {
            out << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n";
        }
    }
    
    bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op, const TType &param)
    {
        return SetFunctionCalled(FunctionId(op, &param));
    }
    
    bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
                                                    const TType &param1,
                                                    const TType &param2)
    {
        return SetFunctionCalled(FunctionId(op, &param1, &param2));
    }
    
    bool BuiltInFunctionEmulator::SetFunctionCalled(TOperator op,
                                                    const TType &param1,
                                                    const TType &param2,
                                                    const TType &param3)
    {
        return SetFunctionCalled(FunctionId(op, &param1, &param2, &param3));
    }
    
    bool BuiltInFunctionEmulator::SetFunctionCalled(const FunctionId &functionId)
    {
        if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end())
        {
            for (size_t i = 0; i < mFunctions.size(); ++i)
            {
                if (mFunctions[i] == functionId)
                    return true;
            }
            // If the function depends on another, mark the dependency as called.
            auto dependency = mFunctionDependencies.find(functionId);
            if (dependency != mFunctionDependencies.end())
            {
                SetFunctionCalled((*dependency).second);
            }
            // Copy the functionId if it needs to be stored, to make sure that the TType pointers inside
            // remain valid and constant.
            mFunctions.push_back(functionId.getCopy());
            return true;
        }
        return false;
    }
    
    void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(TIntermNode *root)
    {
        ASSERT(root);
    
        if (mEmulatedFunctions.empty())
            return;
    
        BuiltInFunctionEmulationMarker marker(*this);
        root->traverse(&marker);
    }
    
    void BuiltInFunctionEmulator::Cleanup()
    {
        mFunctions.clear();
        mFunctionDependencies.clear();
    }
    
    // static
    void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name)
    {
        ASSERT(name[strlen(name) - 1] != '(');
        out << "webgl_" << name << "_emu";
    }
    
    BuiltInFunctionEmulator::FunctionId::FunctionId()
        : mOp(EOpNull),
          mParam1(TCache::getType(EbtVoid)),
          mParam2(TCache::getType(EbtVoid)),
          mParam3(TCache::getType(EbtVoid))
    {
    }
    
    BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op, const TType *param)
        : mOp(op), mParam1(param), mParam2(TCache::getType(EbtVoid)), mParam3(TCache::getType(EbtVoid))
    {
    }
    
    BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
                                                    const TType *param1,
                                                    const TType *param2)
        : mOp(op), mParam1(param1), mParam2(param2), mParam3(TCache::getType(EbtVoid))
    {
    }
    
    BuiltInFunctionEmulator::FunctionId::FunctionId(TOperator op,
                                                    const TType *param1,
                                                    const TType *param2,
                                                    const TType *param3)
        : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3)
    {
    }
    
    bool BuiltInFunctionEmulator::FunctionId::operator==(
        const BuiltInFunctionEmulator::FunctionId &other) const
    {
        return (mOp == other.mOp && *mParam1 == *other.mParam1 && *mParam2 == *other.mParam2 &&
                *mParam3 == *other.mParam3);
    }
    
    bool BuiltInFunctionEmulator::FunctionId::operator<(
        const BuiltInFunctionEmulator::FunctionId &other) const
    {
        if (mOp != other.mOp)
            return mOp < other.mOp;
        if (*mParam1 != *other.mParam1)
            return *mParam1 < *other.mParam1;
        if (*mParam2 != *other.mParam2)
            return *mParam2 < *other.mParam2;
        if (*mParam3 != *other.mParam3)
            return *mParam3 < *other.mParam3;
        return false;  // all fields are equal
    }
    
    BuiltInFunctionEmulator::FunctionId BuiltInFunctionEmulator::FunctionId::getCopy() const
    {
        return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3));
    }
    
    }  // namespace sh