Edit

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

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2020-12-01 11:39:25
    Hash : 8797714c
    Message : Vulkan: Support OES_shader_io_blocks Enables OES/EXT_shader_io_blocks extensions in Vulkan backends. With shader I/O blocks, the varyings can now be an array of struct (the block itself) of struct (nested in the block). This change is missing a number of features. In particular, if the shader I/O block has a location decoration in the middle of the block, that is not handled yet. Based on changes from m.maiya@samsung.com and jmadill@chromium.org. Bug: angleproject:3580 Tests: dEQP-GLES31.functional.shaders.linkage.es31.io_block.* dEQP-GLES31.functional.separate_shader.validation.es31.io_blocks.* dEQP-GLES31.functional.program_interface_query.program_input.* dEQP-GLES31.functional.program_interface_query.program_output.* Change-Id: I593840475d2365ff6c9ce7b2290f5ee462a30dfb Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2567645 Reviewed-by: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> 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.
    //   The shaders are then fed into glslang to spit out SPIR-V (libANGLE-side).
    //   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(TInfoSinkBase &objSink,
                                         ShArrayIndexClampingStrategy clampingStrategy,
                                         ShHashFunction64 hashFunction,
                                         NameMap &nameMap,
                                         TSymbolTable *symbolTable,
                                         sh::GLenum shaderType,
                                         int shaderVersion,
                                         ShShaderOutput output,
                                         bool forceHighp,
                                         bool enablePrecision,
                                         ShCompileOptions compileOptions)
        : TOutputGLSL(objSink,
                      clampingStrategy,
                      hashFunction,
                      nameMap,
                      symbolTable,
                      shaderType,
                      shaderVersion,
                      output,
                      compileOptions),
          mNextUnusedBinding(0),
          mNextUnusedInputLocation(0),
          mNextUnusedOutputLocation(0),
          mForceHighp(forceHighp),
          mEnablePrecision(enablePrecision)
    {}
    
    void TOutputVulkanGLSL::writeLayoutQualifier(TIntermTyped *variable)
    {
        const TType &type = variable->getType();
    
        bool needsSetBinding = IsSampler(type.getBasicType()) ||
                               (type.isInterfaceBlock() && (type.getQualifier() == EvqUniform ||
                                                            type.getQualifier() == EvqBuffer)) ||
                               IsImage(type.getBasicType());
        bool needsLocation = type.getQualifier() == EvqAttribute ||
                             type.getQualifier() == EvqVertexIn ||
                             type.getQualifier() == EvqFragmentOut || IsVarying(type.getQualifier());
    
        if (!NeedsToWriteLayoutQualifier(type) && !needsSetBinding && !needsLocation)
        {
            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.
        TIntermSymbol *symbol = variable->getAsSymbolNode();
        ASSERT(symbol);
    
        ImmutableString name      = symbol->getName();
        const char *blockStorage  = nullptr;
        const char *matrixPacking = nullptr;
    
        // For interface blocks, use the block name instead.  When the layout qualifier is being
        // replaced in the backend, that would be the name that's available.
        if (type.isInterfaceBlock())
        {
            const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
            name                                  = interfaceBlock->name();
            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 requires set & binding layout qualifiers, specify arbitrary
        // ones.
        if (needsSetBinding)
        {
            out << "set=0, binding=" << nextUnusedBinding();
            separator = kCommaSeparator;
        }
    
        if (needsLocation)
        {
            const unsigned int locationCount = CalculateVaryingLocationCount(symbol, getShaderType());
            uint32_t 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(variable);
    
        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);
    }
    
    void TOutputVulkanGLSL::writeStructType(const TStructure *structure)
    {
        if (!structDeclared(structure))
        {
            declareStruct(structure);
            objSink() << ";\n";
        }
    }
    
    bool TOutputVulkanGLSL::writeVariablePrecision(TPrecision precision)
    {
        if ((precision == EbpUndefined) || !mEnablePrecision)
            return false;
    
        TInfoSinkBase &out = objSink();
        if (mForceHighp)
            out << getPrecisionString(EbpHigh);
        else
            out << getPrecisionString(precision);
        return true;
    }
    
    }  // namespace sh