Edit

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

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2021-08-04 10:07:47
    Hash : 061188a7
    Message : Translator: General clean up General clean up done as part of other changes, split to simplify review. Bug: angleproject:4889 Bug: angleproject:6132 Change-Id: Iade9954d187a759be9edd0e3754be007f4133c56 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3071598 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/compiler/translator/OutputVulkanGLSL.cpp
  • //
    // Copyright 2016 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.
    //
    // OutputVulkanGLSL:
    //   Code that outputs shaders that fit GL_KHR_vulkan_glsl, to be fed to glslang to generate
    //   SPIR-V.
    //   See: https://www.khronos.org/registry/vulkan/specs/misc/GL_KHR_vulkan_glsl.txt
    //
    
    #include "compiler/translator/OutputVulkanGLSL.h"
    
    #include "compiler/translator/BaseTypes.h"
    #include "compiler/translator/Symbol.h"
    #include "compiler/translator/ValidateVaryingLocations.h"
    #include "compiler/translator/util.h"
    
    namespace sh
    {
    
    TOutputVulkanGLSL::TOutputVulkanGLSL(TCompiler *compiler,
                                         TInfoSinkBase &objSink,
                                         bool enablePrecision,
                                         ShCompileOptions compileOptions)
        : TOutputGLSL(compiler, objSink, compileOptions),
          mNextUnusedBinding(0),
          mNextUnusedInputLocation(0),
          mNextUnusedOutputLocation(0),
          mEnablePrecision(enablePrecision)
    {}
    
    void TOutputVulkanGLSL::writeLayoutQualifier(TIntermSymbol *symbol)
    {
        const TType &type = symbol->getType();
    
        bool needsSetBinding = IsSampler(type.getBasicType()) ||
                               (type.isInterfaceBlock() && (type.getQualifier() == EvqUniform ||
                                                            type.getQualifier() == EvqBuffer)) ||
                               IsImage(type.getBasicType()) || IsSubpassInputType(type.getBasicType());
        bool needsLocation = type.getQualifier() == EvqAttribute ||
                             type.getQualifier() == EvqVertexIn ||
                             type.getQualifier() == EvqFragmentOut || IsVarying(type.getQualifier());
        bool needsInputAttachmentIndex = IsSubpassInputType(type.getBasicType());
        bool needsSpecConstId          = type.getQualifier() == EvqSpecConst;
    
        if (!NeedsToWriteLayoutQualifier(type) && !needsSetBinding && !needsLocation &&
            !needsInputAttachmentIndex && !needsSpecConstId)
        {
            return;
        }
    
        TInfoSinkBase &out                      = objSink();
        const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
    
        // This isn't super clean, but it gets the job done.
        // See corresponding code in glslang_wrapper_utils.cpp.
        const char *blockStorage  = nullptr;
        const char *matrixPacking = nullptr;
    
        if (type.isInterfaceBlock())
        {
            const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
            TLayoutBlockStorage storage           = interfaceBlock->blockStorage();
    
            // Make sure block storage format is specified.
            if (storage != EbsStd430)
            {
                // Change interface block layout qualifiers to std140 for any layout that is not
                // explicitly set to std430.  This is to comply with GL_KHR_vulkan_glsl where shared and
                // packed are not allowed (and std140 could be used instead) and unspecified layouts can
                // assume either std140 or std430 (and we choose std140 as std430 is not yet universally
                // supported).
                storage = EbsStd140;
            }
    
            if (interfaceBlock->blockStorage() != EbsUnspecified)
            {
                blockStorage = getBlockStorageString(storage);
            }
        }
    
        // Specify matrix packing if necessary.
        if (layoutQualifier.matrixPacking != EmpUnspecified)
        {
            matrixPacking = getMatrixPackingString(layoutQualifier.matrixPacking);
        }
        const char *kCommaSeparator = ", ";
        const char *separator       = "";
        out << "layout(";
    
        // If the resource declaration is about input attachment, need to specify input_attachment_index
        if (needsInputAttachmentIndex)
        {
            out << "input_attachment_index=" << layoutQualifier.inputAttachmentIndex;
            separator = kCommaSeparator;
        }
    
        // If it's a specialization constant, add that constant_id qualifier.
        if (needsSpecConstId)
        {
            out << separator << "constant_id=" << layoutQualifier.location;
        }
    
        // If the resource declaration requires set & binding layout qualifiers, specify arbitrary
        // ones.
        if (needsSetBinding)
        {
            out << separator << "set=0, binding=" << nextUnusedBinding();
            separator = kCommaSeparator;
        }
    
        if (needsLocation)
        {
            uint32_t location = 0;
            if (layoutQualifier.index <= 0)
            {
                // Note: for index == 1 (dual source blending), don't count locations as they are
                // expected to alias the color output locations.  Only one dual-source output is
                // supported, so location will be always 0.
                const unsigned int locationCount =
                    CalculateVaryingLocationCount(symbol->getType(), getShaderType());
                location = IsShaderIn(type.getQualifier()) ? nextUnusedInputLocation(locationCount)
                                                           : nextUnusedOutputLocation(locationCount);
            }
    
            out << separator << "location=" << location;
            separator = kCommaSeparator;
        }
    
        // Output the list of qualifiers already known at this stage, i.e. everything other than
        // `location` and `set`/`binding`.
        std::string otherQualifiers = getCommonLayoutQualifiers(symbol);
    
        if (blockStorage)
        {
            out << separator << blockStorage;
            separator = kCommaSeparator;
        }
        if (matrixPacking)
        {
            out << separator << matrixPacking;
            separator = kCommaSeparator;
        }
        if (!otherQualifiers.empty())
        {
            out << separator << otherQualifiers;
        }
    
        out << ") ";
    }
    
    void TOutputVulkanGLSL::writeVariableType(const TType &type,
                                              const TSymbol *symbol,
                                              bool isFunctionArgument)
    {
        TType overrideType(type);
    
        // External textures are treated as 2D textures in the vulkan back-end
        if (type.getBasicType() == EbtSamplerExternalOES)
        {
            overrideType.setBasicType(EbtSampler2D);
        }
    
        TOutputGLSL::writeVariableType(overrideType, symbol, isFunctionArgument);
    }
    
    bool TOutputVulkanGLSL::writeVariablePrecision(TPrecision precision)
    {
        if ((precision == EbpUndefined) || !mEnablePrecision)
            return false;
    
        TInfoSinkBase &out = objSink();
        out << getPrecisionString(precision);
        return true;
    }
    
    }  // namespace sh