Edit

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

Branch :

  • Show log

    Commit

  • Author : Stuart Morgan
    Date : 2019-08-14 12:25:12
    Hash : 9d737966
    Message : Standardize copyright notices to project style For all "ANGLE Project" copyrights, standardize to the format specified by the style guide. Changes: - "Copyright (c)" and "Copyright(c)" changed to just "Copyright". - Removed the second half of date ranges ("Y1Y1-Y2Y2"->"Y1Y1"). - Fixed a small number of files that had no copyright date using the initial commit year from the version control history. - Fixed one instance of copyright being "The ANGLE Project" rather than "The ANGLE Project Authors" These changes are applied both to the copyright of source file, and where applicable to copyright statements that are generated by templates. BUG=angleproject:3811 Change-Id: I973dd65e4ef9deeba232d5be74c768256a0eb2e5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1754397 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/compiler/translator/UtilsHLSL.cpp
  • //
    // Copyright 2014 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.
    //
    // UtilsHLSL.cpp:
    //   Utility methods for GLSL to HLSL translation.
    //
    
    #include "compiler/translator/UtilsHLSL.h"
    #include "compiler/translator/IntermNode.h"
    #include "compiler/translator/StructureHLSL.h"
    #include "compiler/translator/SymbolTable.h"
    #include "compiler/translator/util.h"
    
    namespace sh
    {
    
    namespace
    {
    
    void DisambiguateFunctionNameForParameterType(const TType &paramType,
                                                  TString *disambiguatingStringOut)
    {
        // Parameter types are only added to function names if they are ambiguous according to the
        // native HLSL compiler. Other parameter types are not added to function names to avoid
        // making function names longer.
        if (paramType.getObjectSize() == 4 && paramType.getBasicType() == EbtFloat)
        {
            // Disambiguation is needed for float2x2 and float4 parameters. These are the only
            // built-in types that HLSL thinks are identical. float2x3 and float3x2 are different
            // types, for example.
            *disambiguatingStringOut += "_" + TypeString(paramType);
        }
        else if (paramType.getBasicType() == EbtStruct)
        {
            // Disambiguation is needed for struct parameters, since HLSL thinks that structs with
            // the same fields but a different name are identical.
            ASSERT(paramType.getStruct()->symbolType() != SymbolType::Empty);
            *disambiguatingStringOut += "_" + TypeString(paramType);
        }
    }
    
    }  // anonymous namespace
    
    const char *SamplerString(const TBasicType type)
    {
        if (IsShadowSampler(type))
        {
            return "SamplerComparisonState";
        }
        else
        {
            return "SamplerState";
        }
    }
    
    const char *SamplerString(HLSLTextureGroup type)
    {
        if (type >= HLSL_COMPARISON_SAMPLER_GROUP_BEGIN && type <= HLSL_COMPARISON_SAMPLER_GROUP_END)
        {
            return "SamplerComparisonState";
        }
        else
        {
            return "SamplerState";
        }
    }
    
    HLSLTextureGroup TextureGroup(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
    
    {
        switch (type)
        {
            case EbtSampler2D:
                return HLSL_TEXTURE_2D;
            case EbtSamplerCube:
                return HLSL_TEXTURE_CUBE;
            case EbtSamplerExternalOES:
                return HLSL_TEXTURE_2D;
            case EbtSampler2DArray:
                return HLSL_TEXTURE_2D_ARRAY;
            case EbtSampler3D:
                return HLSL_TEXTURE_3D;
            case EbtSampler2DMS:
                return HLSL_TEXTURE_2D_MS;
            case EbtSampler2DMSArray:
                return HLSL_TEXTURE_2D_MS_ARRAY;
            case EbtISampler2D:
                return HLSL_TEXTURE_2D_INT4;
            case EbtISampler3D:
                return HLSL_TEXTURE_3D_INT4;
            case EbtISamplerCube:
                return HLSL_TEXTURE_2D_ARRAY_INT4;
            case EbtISampler2DArray:
                return HLSL_TEXTURE_2D_ARRAY_INT4;
            case EbtISampler2DMS:
                return HLSL_TEXTURE_2D_MS_INT4;
            case EbtISampler2DMSArray:
                return HLSL_TEXTURE_2D_MS_ARRAY_INT4;
            case EbtUSampler2D:
                return HLSL_TEXTURE_2D_UINT4;
            case EbtUSampler3D:
                return HLSL_TEXTURE_3D_UINT4;
            case EbtUSamplerCube:
                return HLSL_TEXTURE_2D_ARRAY_UINT4;
            case EbtUSampler2DArray:
                return HLSL_TEXTURE_2D_ARRAY_UINT4;
            case EbtUSampler2DMS:
                return HLSL_TEXTURE_2D_MS_UINT4;
            case EbtUSampler2DMSArray:
                return HLSL_TEXTURE_2D_MS_ARRAY_UINT4;
            case EbtSampler2DShadow:
                return HLSL_TEXTURE_2D_COMPARISON;
            case EbtSamplerCubeShadow:
                return HLSL_TEXTURE_CUBE_COMPARISON;
            case EbtSampler2DArrayShadow:
                return HLSL_TEXTURE_2D_ARRAY_COMPARISON;
            case EbtImage2D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32F:
                    case EiifRGBA16F:
                    case EiifR32F:
                        return HLSL_TEXTURE_2D;
                    case EiifRGBA8:
                        return HLSL_TEXTURE_2D_UNORM;
                    case EiifRGBA8_SNORM:
                        return HLSL_TEXTURE_2D_SNORM;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return HLSL_TEXTURE_UNKNOWN;
    #endif
                }
            }
            case EbtIImage2D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32I:
                    case EiifRGBA16I:
                    case EiifRGBA8I:
                    case EiifR32I:
                        return HLSL_TEXTURE_2D_INT4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return HLSL_TEXTURE_UNKNOWN;
    #endif
                }
            }
            case EbtUImage2D:
            {
                switch (imageInternalFormat)
                {
    
                    case EiifRGBA32UI:
                    case EiifRGBA16UI:
                    case EiifRGBA8UI:
                    case EiifR32UI:
                        return HLSL_TEXTURE_2D_UINT4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return HLSL_TEXTURE_UNKNOWN;
    #endif
                }
            }
            case EbtImage3D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32F:
                    case EiifRGBA16F:
                    case EiifR32F:
                        return HLSL_TEXTURE_3D;
                    case EiifRGBA8:
                        return HLSL_TEXTURE_3D_UNORM;
                    case EiifRGBA8_SNORM:
                        return HLSL_TEXTURE_3D_SNORM;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return HLSL_TEXTURE_UNKNOWN;
    #endif
                }
            }
            case EbtIImage3D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32I:
                    case EiifRGBA16I:
                    case EiifRGBA8I:
                    case EiifR32I:
                        return HLSL_TEXTURE_3D_INT4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return HLSL_TEXTURE_UNKNOWN;
    #endif
                }
            }
            case EbtUImage3D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32UI:
                    case EiifRGBA16UI:
                    case EiifRGBA8UI:
                    case EiifR32UI:
                        return HLSL_TEXTURE_3D_UINT4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return HLSL_TEXTURE_UNKNOWN;
    #endif
                }
            }
            case EbtImage2DArray:
            case EbtImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32F:
                    case EiifRGBA16F:
                    case EiifR32F:
                        return HLSL_TEXTURE_2D_ARRAY;
                    case EiifRGBA8:
                        return HLSL_TEXTURE_2D_ARRAY_UNORN;
                    case EiifRGBA8_SNORM:
                        return HLSL_TEXTURE_2D_ARRAY_SNORM;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return HLSL_TEXTURE_UNKNOWN;
    #endif
                }
            }
            case EbtIImage2DArray:
            case EbtIImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32I:
                    case EiifRGBA16I:
                    case EiifRGBA8I:
                    case EiifR32I:
                        return HLSL_TEXTURE_2D_ARRAY_INT4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return HLSL_TEXTURE_UNKNOWN;
    #endif
                }
            }
            case EbtUImage2DArray:
            case EbtUImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32UI:
                    case EiifRGBA16UI:
                    case EiifRGBA8UI:
                    case EiifR32UI:
                        return HLSL_TEXTURE_2D_ARRAY_UINT4;
                    default:
                        UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                        return HLSL_TEXTURE_UNKNOWN;
    #endif
                }
            }
            default:
                UNREACHABLE();
    #if !UNREACHABLE_IS_NORETURN
                return HLSL_TEXTURE_UNKNOWN;
    #endif
        }
    }
    
    const char *TextureString(const HLSLTextureGroup textureGroup)
    {
        switch (textureGroup)
        {
            case HLSL_TEXTURE_2D:
                return "Texture2D<float4>";
            case HLSL_TEXTURE_CUBE:
                return "TextureCube<float4>";
            case HLSL_TEXTURE_2D_ARRAY:
                return "Texture2DArray<float4>";
            case HLSL_TEXTURE_3D:
                return "Texture3D<float4>";
            case HLSL_TEXTURE_2D_UNORM:
                return "Texture2D<unorm float4>";
            case HLSL_TEXTURE_CUBE_UNORM:
                return "TextureCube<unorm float4>";
            case HLSL_TEXTURE_2D_ARRAY_UNORN:
                return "Texture2DArray<unorm float4>";
            case HLSL_TEXTURE_3D_UNORM:
                return "Texture3D<unorm float4>";
            case HLSL_TEXTURE_2D_SNORM:
                return "Texture2D<snorm float4>";
            case HLSL_TEXTURE_CUBE_SNORM:
                return "TextureCube<snorm float4>";
            case HLSL_TEXTURE_2D_ARRAY_SNORM:
                return "Texture2DArray<snorm float4>";
            case HLSL_TEXTURE_3D_SNORM:
                return "Texture3D<snorm float4>";
            case HLSL_TEXTURE_2D_MS:
                return "Texture2DMS<float4>";
            case HLSL_TEXTURE_2D_MS_ARRAY:
                return "Texture2DMSArray<float4>";
            case HLSL_TEXTURE_2D_INT4:
                return "Texture2D<int4>";
            case HLSL_TEXTURE_3D_INT4:
                return "Texture3D<int4>";
            case HLSL_TEXTURE_2D_ARRAY_INT4:
                return "Texture2DArray<int4>";
            case HLSL_TEXTURE_2D_MS_INT4:
                return "Texture2DMS<int4>";
            case HLSL_TEXTURE_2D_MS_ARRAY_INT4:
                return "Texture2DMSArray<int4>";
            case HLSL_TEXTURE_2D_UINT4:
                return "Texture2D<uint4>";
            case HLSL_TEXTURE_3D_UINT4:
                return "Texture3D<uint4>";
            case HLSL_TEXTURE_2D_ARRAY_UINT4:
                return "Texture2DArray<uint4>";
            case HLSL_TEXTURE_2D_MS_UINT4:
                return "Texture2DMS<uint4>";
            case HLSL_TEXTURE_2D_MS_ARRAY_UINT4:
                return "Texture2DMSArray<uint4>";
            case HLSL_TEXTURE_2D_COMPARISON:
                return "Texture2D";
            case HLSL_TEXTURE_CUBE_COMPARISON:
                return "TextureCube";
            case HLSL_TEXTURE_2D_ARRAY_COMPARISON:
                return "Texture2DArray";
            default:
                UNREACHABLE();
        }
    
        return "<unknown read texture type>";
    }
    
    const char *TextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
    {
        return TextureString(TextureGroup(type, imageInternalFormat));
    }
    
    const char *TextureGroupSuffix(const HLSLTextureGroup type)
    {
        switch (type)
        {
            case HLSL_TEXTURE_2D:
                return "2D";
            case HLSL_TEXTURE_CUBE:
                return "Cube";
            case HLSL_TEXTURE_2D_ARRAY:
                return "2DArray";
            case HLSL_TEXTURE_3D:
                return "3D";
            case HLSL_TEXTURE_2D_UNORM:
                return "2D_unorm_float4_";
            case HLSL_TEXTURE_CUBE_UNORM:
                return "Cube_unorm_float4_";
            case HLSL_TEXTURE_2D_ARRAY_UNORN:
                return "2DArray_unorm_float4_";
            case HLSL_TEXTURE_3D_UNORM:
                return "3D_unorm_float4_";
            case HLSL_TEXTURE_2D_SNORM:
                return "2D_snorm_float4_";
            case HLSL_TEXTURE_CUBE_SNORM:
                return "Cube_snorm_float4_";
            case HLSL_TEXTURE_2D_ARRAY_SNORM:
                return "2DArray_snorm_float4_";
            case HLSL_TEXTURE_3D_SNORM:
                return "3D_snorm_float4_";
            case HLSL_TEXTURE_2D_MS:
                return "2DMS";
            case HLSL_TEXTURE_2D_MS_ARRAY:
                return "2DMSArray";
            case HLSL_TEXTURE_2D_INT4:
                return "2D_int4_";
            case HLSL_TEXTURE_3D_INT4:
                return "3D_int4_";
            case HLSL_TEXTURE_2D_ARRAY_INT4:
                return "2DArray_int4_";
            case HLSL_TEXTURE_2D_MS_INT4:
                return "2DMS_int4_";
            case HLSL_TEXTURE_2D_MS_ARRAY_INT4:
                return "2DMSArray_int4_";
            case HLSL_TEXTURE_2D_UINT4:
                return "2D_uint4_";
            case HLSL_TEXTURE_3D_UINT4:
                return "3D_uint4_";
            case HLSL_TEXTURE_2D_ARRAY_UINT4:
                return "2DArray_uint4_";
            case HLSL_TEXTURE_2D_MS_UINT4:
                return "2DMS_uint4_";
            case HLSL_TEXTURE_2D_MS_ARRAY_UINT4:
                return "2DMSArray_uint4_";
            case HLSL_TEXTURE_2D_COMPARISON:
                return "2D_comparison";
            case HLSL_TEXTURE_CUBE_COMPARISON:
                return "Cube_comparison";
            case HLSL_TEXTURE_2D_ARRAY_COMPARISON:
                return "2DArray_comparison";
            default:
                UNREACHABLE();
        }
    
        return "<unknown texture type>";
    }
    
    const char *TextureGroupSuffix(const TBasicType type,
                                   TLayoutImageInternalFormat imageInternalFormat)
    {
        return TextureGroupSuffix(TextureGroup(type, imageInternalFormat));
    }
    
    const char *TextureTypeSuffix(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
    {
        switch (type)
        {
            case EbtISamplerCube:
                return "Cube_int4_";
            case EbtUSamplerCube:
                return "Cube_uint4_";
            case EbtSamplerExternalOES:
                return "_External";
            case EbtImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32F:
                    case EiifRGBA16F:
                    case EiifR32F:
                        return "Cube_float4_";
                    case EiifRGBA8:
                        return "Cube_unorm_float4_";
                    case EiifRGBA8_SNORM:
                        return "Cube_snorm_float4_";
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtIImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32I:
                    case EiifRGBA16I:
                    case EiifRGBA8I:
                    case EiifR32I:
                        return "Cube_int4_";
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtUImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32UI:
                    case EiifRGBA16UI:
                    case EiifRGBA8UI:
                    case EiifR32UI:
                        return "Cube_uint4_";
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            default:
                // All other types are identified by their group suffix
                return TextureGroupSuffix(type, imageInternalFormat);
        }
    #if !UNREACHABLE_IS_NORETURN
        UNREACHABLE();
        return "_TTS_invalid_";
    #endif
    }
    
    HLSLRWTextureGroup RWTextureGroup(const TBasicType type,
                                      TLayoutImageInternalFormat imageInternalFormat)
    
    {
        switch (type)
        {
            case EbtImage2D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32F:
                    case EiifRGBA16F:
                    case EiifR32F:
                        return HLSL_RWTEXTURE_2D_FLOAT4;
                    case EiifRGBA8:
                        return HLSL_RWTEXTURE_2D_UNORM;
                    case EiifRGBA8_SNORM:
                        return HLSL_RWTEXTURE_2D_SNORM;
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtIImage2D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32I:
                    case EiifRGBA16I:
                    case EiifRGBA8I:
                    case EiifR32I:
                        return HLSL_RWTEXTURE_2D_INT4;
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtUImage2D:
            {
                switch (imageInternalFormat)
                {
    
                    case EiifRGBA32UI:
                    case EiifRGBA16UI:
                    case EiifRGBA8UI:
                    case EiifR32UI:
                        return HLSL_RWTEXTURE_2D_UINT4;
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtImage3D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32F:
                    case EiifRGBA16F:
                    case EiifR32F:
                        return HLSL_RWTEXTURE_3D_FLOAT4;
                    case EiifRGBA8:
                        return HLSL_RWTEXTURE_3D_UNORM;
                    case EiifRGBA8_SNORM:
                        return HLSL_RWTEXTURE_3D_SNORM;
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtIImage3D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32I:
                    case EiifRGBA16I:
                    case EiifRGBA8I:
                    case EiifR32I:
                        return HLSL_RWTEXTURE_3D_INT4;
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtUImage3D:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32UI:
                    case EiifRGBA16UI:
                    case EiifRGBA8UI:
                    case EiifR32UI:
                        return HLSL_RWTEXTURE_3D_UINT4;
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtImage2DArray:
            case EbtImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32F:
                    case EiifRGBA16F:
                    case EiifR32F:
                        return HLSL_RWTEXTURE_2D_ARRAY_FLOAT4;
                    case EiifRGBA8:
                        return HLSL_RWTEXTURE_2D_ARRAY_UNORN;
                    case EiifRGBA8_SNORM:
                        return HLSL_RWTEXTURE_2D_ARRAY_SNORM;
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtIImage2DArray:
            case EbtIImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32I:
                    case EiifRGBA16I:
                    case EiifRGBA8I:
                    case EiifR32I:
                        return HLSL_RWTEXTURE_2D_ARRAY_INT4;
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtUImage2DArray:
            case EbtUImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32UI:
                    case EiifRGBA16UI:
                    case EiifRGBA8UI:
                    case EiifR32UI:
                        return HLSL_RWTEXTURE_2D_ARRAY_UINT4;
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            default:
                UNREACHABLE();
        }
        return HLSL_RWTEXTURE_UNKNOWN;
    }
    
    const char *RWTextureString(const HLSLRWTextureGroup RWTextureGroup)
    {
        switch (RWTextureGroup)
        {
            case HLSL_RWTEXTURE_2D_FLOAT4:
                return "RWTexture2D<float4>";
            case HLSL_RWTEXTURE_2D_ARRAY_FLOAT4:
                return "RWTexture2DArray<float4>";
            case HLSL_RWTEXTURE_3D_FLOAT4:
                return "RWTexture3D<float4>";
            case HLSL_RWTEXTURE_2D_UNORM:
                return "RWTexture2D<unorm float4>";
            case HLSL_RWTEXTURE_2D_ARRAY_UNORN:
                return "RWTexture2DArray<unorm float4>";
            case HLSL_RWTEXTURE_3D_UNORM:
                return "RWTexture3D<unorm float4>";
            case HLSL_RWTEXTURE_2D_SNORM:
                return "RWTexture2D<snorm float4>";
            case HLSL_RWTEXTURE_2D_ARRAY_SNORM:
                return "RWTexture2DArray<snorm float4>";
            case HLSL_RWTEXTURE_3D_SNORM:
                return "RWTexture3D<snorm float4>";
            case HLSL_RWTEXTURE_2D_UINT4:
                return "RWTexture2D<uint4>";
            case HLSL_RWTEXTURE_2D_ARRAY_UINT4:
                return "RWTexture2DArray<uint4>";
            case HLSL_RWTEXTURE_3D_UINT4:
                return "RWTexture3D<uint4>";
            case HLSL_RWTEXTURE_2D_INT4:
                return "RWTexture2D<int4>";
            case HLSL_RWTEXTURE_2D_ARRAY_INT4:
                return "RWTexture2DArray<int4>";
            case HLSL_RWTEXTURE_3D_INT4:
                return "RWTexture3D<int4>";
            default:
                UNREACHABLE();
        }
    
        return "<unknown read and write texture type>";
    }
    
    const char *RWTextureString(const TBasicType type, TLayoutImageInternalFormat imageInternalFormat)
    {
        return RWTextureString(RWTextureGroup(type, imageInternalFormat));
    }
    
    const char *RWTextureGroupSuffix(const HLSLRWTextureGroup type)
    {
        switch (type)
        {
            case HLSL_RWTEXTURE_2D_FLOAT4:
                return "RW2D_float4_";
            case HLSL_RWTEXTURE_2D_ARRAY_FLOAT4:
                return "RW2DArray_float4_";
            case HLSL_RWTEXTURE_3D_FLOAT4:
                return "RW3D_float4_";
            case HLSL_RWTEXTURE_2D_UNORM:
                return "RW2D_unorm_float4_";
            case HLSL_RWTEXTURE_2D_ARRAY_UNORN:
                return "RW2DArray_unorm_float4_";
            case HLSL_RWTEXTURE_3D_UNORM:
                return "RW3D_unorm_float4_";
            case HLSL_RWTEXTURE_2D_SNORM:
                return "RW2D_snorm_float4_";
            case HLSL_RWTEXTURE_2D_ARRAY_SNORM:
                return "RW2DArray_snorm_float4_";
            case HLSL_RWTEXTURE_3D_SNORM:
                return "RW3D_snorm_float4_";
            case HLSL_RWTEXTURE_2D_UINT4:
                return "RW2D_uint4_";
            case HLSL_RWTEXTURE_2D_ARRAY_UINT4:
                return "RW2DArray_uint4_";
            case HLSL_RWTEXTURE_3D_UINT4:
                return "RW3D_uint4_";
            case HLSL_RWTEXTURE_2D_INT4:
                return "RW2D_int4_";
            case HLSL_RWTEXTURE_2D_ARRAY_INT4:
                return "RW2DArray_int4_";
            case HLSL_RWTEXTURE_3D_INT4:
                return "RW3D_int4_";
            default:
                UNREACHABLE();
        }
    
        return "<unknown read and write resource>";
    }
    
    const char *RWTextureGroupSuffix(const TBasicType type,
                                     TLayoutImageInternalFormat imageInternalFormat)
    {
        return RWTextureGroupSuffix(RWTextureGroup(type, imageInternalFormat));
    }
    
    const char *RWTextureTypeSuffix(const TBasicType type,
                                    TLayoutImageInternalFormat imageInternalFormat)
    {
        switch (type)
        {
            case EbtImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32F:
                    case EiifRGBA16F:
                    case EiifR32F:
                        return "RWCube_float4_";
                    case EiifRGBA8:
                        return "RWCube_unorm_float4_";
                    case EiifRGBA8_SNORM:
                        return "RWCube_unorm_float4_";
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtIImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32I:
                    case EiifRGBA16I:
                    case EiifRGBA8I:
                    case EiifR32I:
                        return "RWCube_int4_";
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            case EbtUImageCube:
            {
                switch (imageInternalFormat)
                {
                    case EiifRGBA32UI:
                    case EiifRGBA16UI:
                    case EiifRGBA8UI:
                    case EiifR32UI:
                        return "RWCube_uint4_";
                    default:
                        UNREACHABLE();
                }
    #if !UNREACHABLE_IS_NORETURN
                break;
    #endif
            }
            default:
                // All other types are identified by their group suffix
                return RWTextureGroupSuffix(type, imageInternalFormat);
        }
    #if !UNREACHABLE_IS_NORETURN
        UNREACHABLE();
        return "_RWTS_invalid_";
    #endif
    }
    
    TString DecorateField(const ImmutableString &string, const TStructure &structure)
    {
        if (structure.symbolType() != SymbolType::BuiltIn)
        {
            return Decorate(string);
        }
    
        return TString(string.data());
    }
    
    TString DecoratePrivate(const ImmutableString &privateText)
    {
        return "dx_" + TString(privateText.data());
    }
    
    TString Decorate(const ImmutableString &string)
    {
        if (!string.beginsWith("gl_"))
        {
            return "_" + TString(string.data());
        }
    
        return TString(string.data());
    }
    
    TString DecorateVariableIfNeeded(const TVariable &variable)
    {
        if (variable.symbolType() == SymbolType::AngleInternal ||
            variable.symbolType() == SymbolType::Empty)
        {
            // Besides handling internal variables, we generate names for nameless parameters here.
            const ImmutableString &name = variable.name();
            // The name should not have a prefix reserved for user-defined variables or functions.
            ASSERT(!name.beginsWith("f_"));
            ASSERT(!name.beginsWith("_"));
            return TString(name.data());
        }
        // For user defined variables, combine variable name with unique id
        // so variables of the same name in different scopes do not get overwritten.
        else if (variable.symbolType() == SymbolType::UserDefined &&
                 variable.getType().getQualifier() == EvqTemporary)
        {
            return Decorate(variable.name()) + str(variable.uniqueId().get());
        }
        else
        {
            return Decorate(variable.name());
        }
    }
    
    TString DecorateFunctionIfNeeded(const TFunction *func)
    {
        if (func->symbolType() == SymbolType::AngleInternal)
        {
            // The name should not have a prefix reserved for user-defined variables or functions.
            ASSERT(!func->name().beginsWith("f_"));
            ASSERT(!func->name().beginsWith("_"));
            return TString(func->name().data());
        }
        ASSERT(!func->name().beginsWith("gl_"));
        // Add an additional f prefix to functions so that they're always disambiguated from variables.
        // This is necessary in the corner case where a variable declaration hides a function that it
        // uses in its initializer.
        return "f_" + TString(func->name().data());
    }
    
    TString TypeString(const TType &type)
    {
        const TStructure *structure = type.getStruct();
        if (structure)
        {
            if (structure->symbolType() != SymbolType::Empty)
            {
                return StructNameString(*structure);
            }
            else  // Nameless structure, define in place
            {
                return StructureHLSL::defineNameless(*structure);
            }
        }
        else if (type.isMatrix())
        {
            int cols = type.getCols();
            int rows = type.getRows();
            return "float" + str(cols) + "x" + str(rows);
        }
        else
        {
            switch (type.getBasicType())
            {
                case EbtFloat:
                    switch (type.getNominalSize())
                    {
                        case 1:
                            return "float";
                        case 2:
                            return "float2";
                        case 3:
                            return "float3";
                        case 4:
                            return "float4";
                    }
                case EbtInt:
                    switch (type.getNominalSize())
                    {
                        case 1:
                            return "int";
                        case 2:
                            return "int2";
                        case 3:
                            return "int3";
                        case 4:
                            return "int4";
                    }
                case EbtUInt:
                    switch (type.getNominalSize())
                    {
                        case 1:
                            return "uint";
                        case 2:
                            return "uint2";
                        case 3:
                            return "uint3";
                        case 4:
                            return "uint4";
                    }
                case EbtBool:
                    switch (type.getNominalSize())
                    {
                        case 1:
                            return "bool";
                        case 2:
                            return "bool2";
                        case 3:
                            return "bool3";
                        case 4:
                            return "bool4";
                    }
                case EbtVoid:
                    return "void";
                case EbtSampler2D:
                case EbtISampler2D:
                case EbtUSampler2D:
                case EbtSampler2DArray:
                case EbtISampler2DArray:
                case EbtUSampler2DArray:
                    return "sampler2D";
                case EbtSamplerCube:
                case EbtISamplerCube:
                case EbtUSamplerCube:
                    return "samplerCUBE";
                case EbtSamplerExternalOES:
                    return "sampler2D";
                case EbtAtomicCounter:
                    // Multiple atomic_uints will be implemented as a single RWByteAddressBuffer
                    return "RWByteAddressBuffer";
                default:
                    break;
            }
        }
    
        UNREACHABLE();
        return "<unknown type>";
    }
    
    TString StructNameString(const TStructure &structure)
    {
        if (structure.symbolType() == SymbolType::Empty)
        {
            return "";
        }
    
        // For structures at global scope we use a consistent
        // translation so that we can link between shader stages.
        if (structure.atGlobalScope())
        {
            return Decorate(structure.name());
        }
    
        return "ss" + str(structure.uniqueId().get()) + "_" + TString(structure.name().data());
    }
    
    TString QualifiedStructNameString(const TStructure &structure,
                                      bool useHLSLRowMajorPacking,
                                      bool useStd140Packing)
    {
        if (structure.symbolType() == SymbolType::Empty)
        {
            return "";
        }
    
        TString prefix = "";
    
        // Structs packed with row-major matrices in HLSL are prefixed with "rm"
        // GLSL column-major maps to HLSL row-major, and the converse is true
    
        if (useStd140Packing)
        {
            prefix += "std_";
        }
    
        if (useHLSLRowMajorPacking)
        {
            prefix += "rm_";
        }
    
        return prefix + StructNameString(structure);
    }
    
    const char *InterpolationString(TQualifier qualifier)
    {
        switch (qualifier)
        {
            case EvqVaryingIn:
                return "";
            case EvqFragmentIn:
                return "";
            case EvqSmoothIn:
                return "linear";
            case EvqFlatIn:
                return "nointerpolation";
            case EvqCentroidIn:
                return "centroid";
            case EvqVaryingOut:
                return "";
            case EvqVertexOut:
                return "";
            case EvqSmoothOut:
                return "linear";
            case EvqFlatOut:
                return "nointerpolation";
            case EvqCentroidOut:
                return "centroid";
            default:
                UNREACHABLE();
        }
    
        return "";
    }
    
    const char *QualifierString(TQualifier qualifier)
    {
        switch (qualifier)
        {
            case EvqIn:
                return "in";
            case EvqOut:
                return "inout";  // 'out' results in an HLSL error if not all fields are written, for
                                 // GLSL it's undefined
            case EvqInOut:
                return "inout";
            case EvqConstReadOnly:
                return "const";
            default:
                UNREACHABLE();
        }
    
        return "";
    }
    
    TString DisambiguateFunctionName(const TFunction *func)
    {
        TString disambiguatingString;
        size_t paramCount = func->getParamCount();
        for (size_t i = 0; i < paramCount; ++i)
        {
            DisambiguateFunctionNameForParameterType(func->getParam(i)->getType(),
                                                     &disambiguatingString);
        }
        return disambiguatingString;
    }
    
    TString DisambiguateFunctionName(const TIntermSequence *args)
    {
        TString disambiguatingString;
        for (TIntermNode *arg : *args)
        {
            ASSERT(arg->getAsTyped());
            DisambiguateFunctionNameForParameterType(arg->getAsTyped()->getType(),
                                                     &disambiguatingString);
        }
        return disambiguatingString;
    }
    
    }  // namespace sh