Edit

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

Branch :

  • Show log

    Commit

  • Author : Xinghua Cao
    Date : 2019-09-03 16:24:45
    Hash : 0af8b596
    Message : D3D11: Translate uniform blocks to StructuredBuffer when necessary fxc exhibits slow compile performance with dynamic cbuffer indexing. So when a uniform block contains only one large array member, which is an array of structures, translate this uniform block to a StructuredBuffer instead. Bug: angleproject:3682 TEST=angle_end2end_tests.UniformBufferTest.* Change-Id: Ife80dba8aae65b761737e095895e00a570230f88 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1782046 Commit-Queue: Xinghua Cao <xinghua.cao@intel.com> Reviewed-by: Kenneth Russell <kbr@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@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:
            case EbtSamplerVideoWEBGL:
                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 EbtSamplerVideoWEBGL:
                    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,
                                      bool forcePackingEnd)
    {
        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_";
        }
    
        if (forcePackingEnd)
        {
            prefix += "pe_";
        }
    
        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