Edit

kc3-lang/angle/src/compiler/translator/TranslatorMetalDirect/Pipeline.cpp

Branch :

  • Show log

    Commit

  • Author : Kyle Piddington
    Date : 2021-04-26 16:56:15
    Hash : d7aa0130
    Message : Upstream Apple's direct-to-Metal backend: compile translator. This change is meant to merge the translator changes from Apple's direct-to-Metal backend. Taken from Kyle Piddington's CL: https://chromium-review.googlesource.com/c/angle/angle/+/2857366/ The goal of this CL is to merge the translator code in a state that compiles, but not to switch the Metal backend over to use this translator backend yet. Bug: angleproject:5505 Change-Id: I68a6354604498cd5fd1eb96c13fc56f3b38f2bd0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2897536 Reviewed-by: Jonah Ryan-Davis <jonahr@google.com> Commit-Queue: Jonah Ryan-Davis <jonahr@google.com>

  • src/compiler/translator/TranslatorMetalDirect/Pipeline.cpp
  • //
    // Copyright 2020 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 "compiler/translator/TranslatorMetalDirect/Pipeline.h"
    #include "compiler/translator/tree_util/BuiltIn.h"
    
    using namespace sh;
    
    ////////////////////////////////////////////////////////////////////////////////
    
    #define VARIANT_NAME(variant, base) (variant == Variant::Modified ? base "Mod" : base)
    
    bool Pipeline::uses(const TVariable &var) const
    {
        if (var.symbolType() == SymbolType::Empty)
        {
            return false;
        }
    
        if (globalInstanceVar)
        {
            return &var == globalInstanceVar;
        }
    
        const TType &nodeType      = var.getType();
        const TQualifier qualifier = nodeType.getQualifier();
    
        switch (type)
        {
            case Type::VertexIn:
                switch (qualifier)
                {
                    case TQualifier::EvqAttribute:
                    case TQualifier::EvqVertexIn:
                        return true;
                    default:
                        return false;
                }
    
            case Type::VertexOut:
                switch (qualifier)
                {
                    case TQualifier::EvqVertexOut:
                    case TQualifier::EvqPosition:
                    case TQualifier::EvqFlatOut:
                    case TQualifier::EvqPointSize:
                    case TQualifier::EvqSmoothOut:
                    case TQualifier::EvqCentroidOut:
                    case TQualifier::EvqNoPerspectiveOut:
                    case TQualifier::EvqVaryingOut:
                        return true;
                    default:
                        return false;
                }
    
            case Type::FragmentIn:
                switch (qualifier)
                {
                    case TQualifier::EvqFragmentIn:
                    case TQualifier::EvqFlatIn:
                    case TQualifier::EvqSmoothIn:
                    case TQualifier::EvqCentroidIn:
                    case TQualifier::EvqNoPerspectiveIn:
                    case TQualifier::EvqVaryingIn:
                        return true;
                    default:
                        return false;
                }
    
            case Type::FragmentOut:
                switch (qualifier)
                {
                    case TQualifier::EvqFragmentOut:
                    case TQualifier::EvqFragColor:
                    case TQualifier::EvqFragData:
                    case TQualifier::EvqFragDepth:
                    case TQualifier::EvqSampleMask:
                        return true;
                    default:
                        return false;
                }
    
            case Type::UserUniforms:
                switch (qualifier)
                {
                    case TQualifier::EvqUniform:
                        return true;
                    default:
                        return false;
                }
    
            case Type::NonConstantGlobals:
                switch (qualifier)
                {
                    case TQualifier::EvqGlobal:
                        return true;
                    default:
                        return false;
                }
    
            case Type::InvocationVertexGlobals:
                switch (qualifier)
                {
                    case TQualifier::EvqVertexID:
                        return true;
                    default:
                        return false;
                }
    
            case Type::InvocationFragmentGlobals:
                switch (qualifier)
                {
                    case TQualifier::EvqFragCoord:
                    case TQualifier::EvqPointCoord:
                    case TQualifier::EvqFrontFacing:
                        return true;
                    default:
                        return false;
                }
    
            case Type::UniformBuffer:
                switch (qualifier)
                {
                    case TQualifier::EvqBuffer:
                        return true;
                    default:
                        return false;
                }
            case Type::AngleUniforms:
                UNREACHABLE();  // globalInstanceVar should be non-null and thus never reach here.
                return false;
    
            case Type::Texture:
                return IsSampler(nodeType.getBasicType());
    
            case Type::InstanceId:
                return Name(var) == Name(*BuiltInVariable::gl_InstanceID());
        }
    }
    
    Name Pipeline::getStructTypeName(Variant variant) const
    {
        const char *name;
        switch (type)
        {
            case Type::VertexIn:
                name = VARIANT_NAME(variant, "VertexIn");
                break;
            case Type::VertexOut:
                name = VARIANT_NAME(variant, "VertexOut");
                break;
            case Type::FragmentIn:
                name = VARIANT_NAME(variant, "FragmentIn");
                break;
            case Type::FragmentOut:
                name = VARIANT_NAME(variant, "FragmentOut");
                break;
            case Type::UserUniforms:
                name = VARIANT_NAME(variant, "UserUniforms");
                break;
            case Type::AngleUniforms:
                name = VARIANT_NAME(variant, "AngleUniforms");
                break;
            case Type::NonConstantGlobals:
                name = VARIANT_NAME(variant, "NonConstGlobals");
                break;
            case Type::InvocationVertexGlobals:
                name = VARIANT_NAME(variant, "InvocationVertexGlobals");
                break;
            case Type::InvocationFragmentGlobals:
                name = VARIANT_NAME(variant, "InvocationFragmentGlobals");
                break;
            case Type::Texture:
                name = VARIANT_NAME(variant, "TextureEnvs");
                break;
            case Type::InstanceId:
                name = VARIANT_NAME(variant, "InstanceId");
                break;
            case Type::UniformBuffer:
                name = VARIANT_NAME(variant, "UniformBuffer");
        }
        return Name(name);
    }
    
    Name Pipeline::getStructInstanceName(Variant variant) const
    {
        const char *name;
        switch (type)
        {
            case Type::VertexIn:
                name = VARIANT_NAME(variant, "vertexIn");
                break;
            case Type::VertexOut:
                name = VARIANT_NAME(variant, "vertexOut");
                break;
            case Type::FragmentIn:
                name = VARIANT_NAME(variant, "fragmentIn");
                break;
            case Type::FragmentOut:
                name = VARIANT_NAME(variant, "fragmentOut");
                break;
            case Type::UserUniforms:
                name = VARIANT_NAME(variant, "userUniforms");
                break;
            case Type::AngleUniforms:
                name = VARIANT_NAME(variant, "angleUniforms");
                break;
            case Type::NonConstantGlobals:
                name = VARIANT_NAME(variant, "nonConstGlobals");
                break;
            case Type::InvocationVertexGlobals:
                name = VARIANT_NAME(variant, "invocationVertexGlobals");
                break;
            case Type::InvocationFragmentGlobals:
                name = VARIANT_NAME(variant, "invocationFragmentGlobals");
                break;
            case Type::Texture:
                name = VARIANT_NAME(variant, "textureEnvs");
                break;
            case Type::InstanceId:
                name = VARIANT_NAME(variant, "instanceId");
                break;
            case Type::UniformBuffer:
                name = VARIANT_NAME(variant, "uniformBuffer");
        }
        return Name(name);
    }
    
    static bool AllowPacking(Pipeline::Type type)
    {
        using Type = Pipeline::Type;
    
        switch (type)
        {
            case Type::UniformBuffer:
            case Type::UserUniforms:
                return true;
    
            case Type::VertexIn:
            case Type::VertexOut:
            case Type::FragmentIn:
            case Type::FragmentOut:
            case Type::AngleUniforms:
            case Type::NonConstantGlobals:
            case Type::InvocationVertexGlobals:
            case Type::InvocationFragmentGlobals:
            case Type::Texture:
            case Type::InstanceId:
                return false;
        }
    }
    
    static bool AllowPadding(Pipeline::Type type)
    {
        using Type = Pipeline::Type;
    
        switch (type)
        {
            case Type::UserUniforms:
            case Type::VertexIn:
            case Type::VertexOut:
            case Type::FragmentIn:
            case Type::FragmentOut:
            case Type::AngleUniforms:
            case Type::NonConstantGlobals:
            case Type::InvocationVertexGlobals:
            case Type::InvocationFragmentGlobals:
            case Type::UniformBuffer:
                return true;
    
            case Type::Texture:
            case Type::InstanceId:
                return false;
        }
    }
    enum Compare
    {
        LT,
        LTE,
        EQ,
        GTE,
        GT,
    };
    
    template <typename T>
    static bool CompareBy(Compare op, const T &x, const T &y)
    {
        switch (op)
        {
            case LT:
                return x < y;
            case LTE:
                return x <= y;
            case EQ:
                return x == y;
            case GTE:
                return x >= y;
            case GT:
                return x > y;
        }
    }
    
    template <TBasicType BT, Compare Cmp, int MatchDim, int NewDim>
    static int SaturateVectorOf(const TField &field)
    {
        static_assert(NewDim >= MatchDim, "");
    
        const TType &type = *field.type();
        ASSERT(type.isScalar() || type.isVector());
    
        const bool cond = type.getBasicType() == BT && !type.isArray() &&
                          CompareBy(Cmp, type.getNominalSize(), MatchDim) &&
                          type.getQualifier() != TQualifier::EvqFragDepth;
    
        if (cond)
        {
            return NewDim;
        }
        return 0;
    }
    
    ModifyStructConfig Pipeline::externalStructModifyConfig() const
    {
        using Pred   = ModifyStructConfig::Predicate;
        using SatVec = ModifyStructConfig::SaturateVector;
    
        ModifyStructConfig config(
            isPipelineOut() ? ConvertType::OriginalToModified : ConvertType::ModifiedToOriginal,
            AllowPacking(type), AllowPadding(type));
    
        config.externalAddressSpace = externalAddressSpace();
    
        switch (type)
        {
            case Type::VertexIn:
                config.inlineArray        = Pred::True;
                config.splitMatrixColumns = Pred::True;
                config.inlineStruct       = Pred::True;
                break;
    
            case Type::VertexOut:
                config.inlineArray        = Pred::True;
                config.splitMatrixColumns = Pred::True;
                config.inlineStruct       = Pred::True;
                break;
    
            case Type::FragmentIn:
                config.inlineArray        = Pred::True;
                config.splitMatrixColumns = Pred::True;
                config.inlineStruct       = Pred::True;
                break;
    
            case Type::FragmentOut:
                config.inlineArray            = Pred::True;
                config.splitMatrixColumns     = Pred::True;
                config.inlineStruct           = Pred::True;
                config.saturateScalarOrVector = [](const TField &field) {
                    if (field.type()->getQualifier() == TQualifier::EvqSampleMask)
                    {
                        return 1;
                    }
                    if (int s = SaturateVectorOf<TBasicType::EbtInt, LT, 4, 4>(field))
                    {
                        return s;
                    }
                    if (int s = SaturateVectorOf<TBasicType::EbtUInt, LT, 4, 4>(field))
                    {
                        return s;
                    }
                    if (int s = SaturateVectorOf<TBasicType::EbtFloat, LT, 4, 4>(field))
                    {
                        return s;
                    }
                    return 0;
                };
                break;
            case Type::UserUniforms:
                config.promoteBoolToUint            = Pred::True;
                config.saturateMatrixRows           = SatVec::FullySaturate;
                config.saturateScalarOrVectorArrays = SatVec::FullySaturate;
                config.recurseStruct                = Pred::True;
                break;
    
            case Type::AngleUniforms:
                config.initialBlockStorage = TLayoutBlockStorage::EbsStd430;  // XXX: Correct?
                break;
    
            case Type::NonConstantGlobals:
                break;
            case Type::UniformBuffer:
                config.promoteBoolToUint            = Pred::True;
                config.saturateMatrixRows           = SatVec::FullySaturate;
                config.saturateScalarOrVectorArrays = SatVec::FullySaturate;
                config.recurseStruct                = Pred::True;
                break;
            case Type::InvocationVertexGlobals:
            case Type::InvocationFragmentGlobals:
            case Type::Texture:
            case Type::InstanceId:
                break;
        }
    
        return config;
    }
    
    bool Pipeline::alwaysRequiresLocalVariableDeclarationInMain() const
    {
        switch (type)
        {
            case Type::VertexIn:
            case Type::FragmentIn:
            case Type::UserUniforms:
            case Type::AngleUniforms:
            case Type::UniformBuffer:
                return false;
    
            case Type::VertexOut:
            case Type::FragmentOut:
            case Type::NonConstantGlobals:
            case Type::InvocationVertexGlobals:
            case Type::InvocationFragmentGlobals:
            case Type::Texture:
            case Type::InstanceId:
                return true;
        }
    }
    
    bool Pipeline::isPipelineOut() const
    {
        switch (type)
        {
            case Type::VertexIn:
            case Type::FragmentIn:
            case Type::UserUniforms:
            case Type::AngleUniforms:
            case Type::NonConstantGlobals:
            case Type::InvocationVertexGlobals:
            case Type::InvocationFragmentGlobals:
            case Type::Texture:
            case Type::InstanceId:
            case Type::UniformBuffer:
                return false;
    
            case Type::VertexOut:
            case Type::FragmentOut:
                return true;
        }
    }
    
    AddressSpace Pipeline::externalAddressSpace() const
    {
        switch (type)
        {
            case Type::VertexIn:
            case Type::FragmentIn:
            case Type::NonConstantGlobals:
            case Type::InvocationVertexGlobals:
            case Type::InvocationFragmentGlobals:
            case Type::Texture:
            case Type::InstanceId:
            case Type::FragmentOut:
            case Type::VertexOut:
                return AddressSpace::Thread;
    
            case Type::UserUniforms:
            case Type::AngleUniforms:
            case Type::UniformBuffer:
                return AddressSpace::Constant;
        }
    }
    
    bool PipelineStructs::matches(const TStructure &s, bool internal, bool external) const
    {
        PipelineScoped<TStructure> ps[] = {
            fragmentIn,
            fragmentOut,
            vertexIn,
            vertexOut,
            userUniforms,
            /* angleUniforms, */
            nonConstantGlobals,
            invocationVertexGlobals,
            invocationFragmentGlobals,
            uniformBuffers,
            texture,
            instanceId,
        };
        for (const auto &p : ps)
        {
            if (internal && p.internal == &s)
            {
                return true;
            }
            if (external && p.external == &s)
            {
                return true;
            }
        }
        return false;
    }