588 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			588 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
 | 
						|
#include "iwa/util/reflect_glsl.hpp"
 | 
						|
 | 
						|
#include <glslang/Include/InfoSink.h>
 | 
						|
#include <glslang/Public/ShaderLang.h>
 | 
						|
#include <glslang/MachineIndependent/localintermediate.h>
 | 
						|
#include <glslang/Public/ResourceLimits.h>
 | 
						|
 | 
						|
namespace iwa
 | 
						|
{
 | 
						|
namespace
 | 
						|
{
 | 
						|
class MetaCollectingTraverser : public glslang::TIntermTraverser
 | 
						|
{
 | 
						|
private:
 | 
						|
    ShaderMeta& meta;
 | 
						|
    vk::ShaderStageFlagBits shaderType;
 | 
						|
public:
 | 
						|
    inline MetaCollectingTraverser(ShaderMeta& meta_, vk::ShaderStageFlagBits shaderType_) : meta(meta_), shaderType(shaderType_)
 | 
						|
    {}
 | 
						|
 | 
						|
    bool visitBinary(glslang::TVisit, glslang::TIntermBinary* node) override;
 | 
						|
    bool visitUnary(glslang::TVisit, glslang::TIntermUnary* node) override;
 | 
						|
    bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate* node) override;
 | 
						|
    bool visitSelection(glslang::TVisit, glslang::TIntermSelection* node) override;
 | 
						|
    void visitConstantUnion(glslang::TIntermConstantUnion* node) override;
 | 
						|
    void visitSymbol(glslang::TIntermSymbol* node) override;
 | 
						|
    bool visitLoop(glslang::TVisit, glslang::TIntermLoop* node) override;
 | 
						|
    bool visitBranch(glslang::TVisit, glslang::TIntermBranch* node) override;
 | 
						|
    bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch* node) override;
 | 
						|
};
 | 
						|
 | 
						|
vk::Format convertGlslangBaseType(const glslang::TType& type)
 | 
						|
{
 | 
						|
    switch (type.getBasicType())
 | 
						|
    {
 | 
						|
        case glslang::EbtInt:
 | 
						|
            return vk::Format::eR32Sint;
 | 
						|
        case glslang::EbtUint:
 | 
						|
            return vk::Format::eR32Uint;
 | 
						|
        case glslang::EbtFloat:
 | 
						|
            return vk::Format::eR32Sfloat;
 | 
						|
        case glslang::EbtDouble:
 | 
						|
            return vk::Format::eR64Sfloat;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    logAndDie("Don't know how to convert Glslang basic type :*(");
 | 
						|
}
 | 
						|
 | 
						|
vk::Format convertGlslangLayoutFormat(glslang::TLayoutFormat layoutFormat)
 | 
						|
{
 | 
						|
    switch (layoutFormat)
 | 
						|
    {
 | 
						|
        case glslang::TLayoutFormat::ElfNone:
 | 
						|
            return vk::Format::eUndefined;
 | 
						|
 | 
						|
            // Float image
 | 
						|
        case glslang::TLayoutFormat::ElfRgba32f:
 | 
						|
            return vk::Format::eR32G32B32A32Sfloat;
 | 
						|
        case glslang::TLayoutFormat::ElfRgba16f:
 | 
						|
            return vk::Format::eR16G16B16A16Sfloat;
 | 
						|
        case glslang::TLayoutFormat::ElfR32f:
 | 
						|
            return vk::Format::eR32Sfloat;
 | 
						|
        case glslang::TLayoutFormat::ElfRgba8:
 | 
						|
            return vk::Format::eR8G8B8A8Unorm;
 | 
						|
        case glslang::TLayoutFormat::ElfRgba8Snorm:
 | 
						|
            return vk::Format::eR8G8B8A8Snorm;
 | 
						|
 | 
						|
 | 
						|
        case glslang::TLayoutFormat::ElfRg32f:
 | 
						|
            return vk::Format::eR32G32Sfloat;
 | 
						|
        case glslang::TLayoutFormat::ElfRg16f:
 | 
						|
            return vk::Format::eR16G16Sfloat;
 | 
						|
        case glslang::TLayoutFormat::ElfR11fG11fB10f:
 | 
						|
            return vk::Format::eB10G11R11UfloatPack32; // TODO: ?
 | 
						|
        case glslang::TLayoutFormat::ElfR16f:
 | 
						|
            return vk::Format::eR16Sfloat;
 | 
						|
        case glslang::TLayoutFormat::ElfRgba16:
 | 
						|
            return vk::Format::eR16G16B16A16Unorm;
 | 
						|
        case glslang::TLayoutFormat::ElfRgb10A2:
 | 
						|
            return vk::Format::eA2R10G10B10SnormPack32; // TODO: ?
 | 
						|
        case glslang::TLayoutFormat::ElfRg16:
 | 
						|
            return vk::Format::eR16G16Unorm;
 | 
						|
        case glslang::TLayoutFormat::ElfRg8:
 | 
						|
            return vk::Format::eR8G8Unorm;
 | 
						|
        case glslang::TLayoutFormat::ElfR16:
 | 
						|
            return vk::Format::eR16Unorm;
 | 
						|
        case glslang::TLayoutFormat::ElfR8:
 | 
						|
            return vk::Format::eR8Unorm;
 | 
						|
        case glslang::TLayoutFormat::ElfRgba16Snorm:
 | 
						|
            return vk::Format::eR16G16B16A16Snorm;
 | 
						|
        case glslang::TLayoutFormat::ElfRg16Snorm:
 | 
						|
            return vk::Format::eR16G16Unorm;
 | 
						|
        case glslang::TLayoutFormat::ElfRg8Snorm:
 | 
						|
            return vk::Format::eR8G8Snorm;
 | 
						|
        case glslang::TLayoutFormat::ElfR16Snorm:
 | 
						|
            return vk::Format::eR16G16Snorm;
 | 
						|
        case glslang::TLayoutFormat::ElfR8Snorm:
 | 
						|
            return vk::Format::eR8Snorm;
 | 
						|
 | 
						|
            // Int image
 | 
						|
        case glslang::TLayoutFormat::ElfRgba32i:
 | 
						|
            return vk::Format::eR32G32B32A32Sint;
 | 
						|
        case glslang::TLayoutFormat::ElfRgba16i:
 | 
						|
            return vk::Format::eR16G16B16A16Sint;
 | 
						|
        case glslang::TLayoutFormat::ElfRgba8i:
 | 
						|
            return vk::Format::eR8G8B8A8Sint;
 | 
						|
        case glslang::TLayoutFormat::ElfR32i:
 | 
						|
            return vk::Format::eR32Sint;
 | 
						|
 | 
						|
        case glslang::TLayoutFormat::ElfRg32i:
 | 
						|
            return vk::Format::eR32G32Sint;
 | 
						|
        case glslang::TLayoutFormat::ElfRg16i:
 | 
						|
            return vk::Format::eR16G16Sint;
 | 
						|
        case glslang::TLayoutFormat::ElfRg8i:
 | 
						|
            return vk::Format::eR8G8Sint;
 | 
						|
        case glslang::TLayoutFormat::ElfR16i:
 | 
						|
            return vk::Format::eR16Sint;
 | 
						|
        case glslang::TLayoutFormat::ElfR8i:
 | 
						|
            return vk::Format::eR8Sint;
 | 
						|
        case glslang::TLayoutFormat::ElfR64i:
 | 
						|
            return vk::Format::eR64Sint;
 | 
						|
 | 
						|
            // Uint image
 | 
						|
        case glslang::TLayoutFormat::ElfRgba32ui:
 | 
						|
            return vk::Format::eR32G32B32A32Uint;
 | 
						|
        case glslang::TLayoutFormat::ElfRgba16ui:
 | 
						|
            return vk::Format::eR16G16B16A16Uint;
 | 
						|
        case glslang::TLayoutFormat::ElfRgba8ui:
 | 
						|
            return vk::Format::eR8G8B8A8Uint;
 | 
						|
        case glslang::TLayoutFormat::ElfR32ui:
 | 
						|
            return vk::Format::eR32Uint;
 | 
						|
 | 
						|
 | 
						|
        case glslang::TLayoutFormat::ElfRg32ui:
 | 
						|
            return vk::Format::eR32G32Uint;
 | 
						|
        case glslang::TLayoutFormat::ElfRg16ui:
 | 
						|
            return vk::Format::eR16G16Uint;
 | 
						|
        case glslang::TLayoutFormat::ElfRgb10a2ui:
 | 
						|
            return vk::Format::eA2R10G10B10UintPack32;
 | 
						|
        case glslang::TLayoutFormat::ElfRg8ui:
 | 
						|
            return vk::Format::eR8G8Uint;
 | 
						|
        case glslang::TLayoutFormat::ElfR16ui:
 | 
						|
            return vk::Format::eR16Uint;
 | 
						|
        case glslang::TLayoutFormat::ElfR8ui:
 | 
						|
            return vk::Format::eR8Uint;
 | 
						|
        case glslang::TLayoutFormat::ElfR64ui:
 | 
						|
            return vk::Format::eR64Uint;
 | 
						|
 | 
						|
            // other/unknown
 | 
						|
        case glslang::TLayoutFormat::ElfSize1x8:
 | 
						|
        case glslang::TLayoutFormat::ElfSize1x16:
 | 
						|
        case glslang::TLayoutFormat::ElfSize1x32:
 | 
						|
        case glslang::TLayoutFormat::ElfSize2x32:
 | 
						|
        case glslang::TLayoutFormat::ElfSize4x32:
 | 
						|
        case glslang::TLayoutFormat::ElfEsFloatGuard:
 | 
						|
        case glslang::TLayoutFormat::ElfFloatGuard:
 | 
						|
        case glslang::TLayoutFormat::ElfEsIntGuard:
 | 
						|
        case glslang::TLayoutFormat::ElfIntGuard:
 | 
						|
        case glslang::TLayoutFormat::ElfEsUintGuard:
 | 
						|
        case glslang::TLayoutFormat::ElfExtSizeGuard:
 | 
						|
        case glslang::TLayoutFormat::ElfCount:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    logAndDie("Unexpected format in convertGlslangLayoutFormat()."); // : {}", layoutFormat);
 | 
						|
}
 | 
						|
 | 
						|
vk::Format convertGlslangVectorType(glslang::TBasicType basicType, int vectorSize)
 | 
						|
{
 | 
						|
    switch (basicType)
 | 
						|
    {
 | 
						|
        case glslang::EbtFloat:
 | 
						|
            switch (vectorSize)
 | 
						|
            {
 | 
						|
                case 2:
 | 
						|
                    return vk::Format::eR32G32Sfloat;
 | 
						|
                case 3:
 | 
						|
                    return vk::Format::eR32G32B32Sfloat;
 | 
						|
                case 4:
 | 
						|
                    return vk::Format::eR32G32B32A32Sfloat;
 | 
						|
                default:
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case glslang::EbtDouble:
 | 
						|
            switch (vectorSize)
 | 
						|
            {
 | 
						|
                case 2:
 | 
						|
                    return vk::Format::eR64G64Sfloat;
 | 
						|
                case 3:
 | 
						|
                    return vk::Format::eR64G64B64Sfloat;
 | 
						|
                case 4:
 | 
						|
                    return vk::Format::eR64G64B64A64Sfloat;
 | 
						|
                default:
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case glslang::EbtInt:
 | 
						|
            switch (vectorSize)
 | 
						|
            {
 | 
						|
                case 2:
 | 
						|
                    return vk::Format::eR32G32Sint;
 | 
						|
                case 3:
 | 
						|
                    return vk::Format::eR32G32B32Sint;
 | 
						|
                case 4:
 | 
						|
                    return vk::Format::eR32G32B32A32Sint;
 | 
						|
                default:
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case glslang::EbtUint:
 | 
						|
            switch (vectorSize)
 | 
						|
            {
 | 
						|
                case 2:
 | 
						|
                    return vk::Format::eR32G32Uint;
 | 
						|
                case 3:
 | 
						|
                    return vk::Format::eR32G32B32Uint;
 | 
						|
                case 4:
 | 
						|
                    return vk::Format::eR32G32B32A32Uint;
 | 
						|
                default:
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case glslang::EbtBool: // NOLINT(bugprone-branch-clone) TODO: ???
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    logAndDie("Don't know how to convert Glslang vector type :(");
 | 
						|
}
 | 
						|
 | 
						|
vk::Format convertGlslangVectorType(const glslang::TType& type)
 | 
						|
{
 | 
						|
    assert(type.isVector());
 | 
						|
    return convertGlslangVectorType(type.getBasicType(), type.getVectorSize());
 | 
						|
}
 | 
						|
 | 
						|
ShaderVariableMatrixType convertGlslangMatrixType(const glslang::TType& type)
 | 
						|
{
 | 
						|
    assert(type.isMatrix());
 | 
						|
    assert(type.getMatrixCols() == type.getMatrixRows()); // only supported types yet...
 | 
						|
    switch (type.getMatrixCols())
 | 
						|
    {
 | 
						|
        case 2:
 | 
						|
            return ShaderVariableMatrixType::MAT2;
 | 
						|
        case 3:
 | 
						|
            return ShaderVariableMatrixType::MAT3;
 | 
						|
        case 4:
 | 
						|
            return ShaderVariableMatrixType::MAT4;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    logAndDie("Don't know how to convert Glslang matrix type -.-");
 | 
						|
}
 | 
						|
 | 
						|
ImageDim convertGlslangSamplerDim(glslang::TSamplerDim dim)
 | 
						|
{
 | 
						|
    switch (dim)
 | 
						|
    {
 | 
						|
        case glslang::TSamplerDim::Esd1D:
 | 
						|
            return ImageDim::ONE;
 | 
						|
        case glslang::TSamplerDim::Esd2D:
 | 
						|
            return ImageDim::TWO;
 | 
						|
        case glslang::TSamplerDim::Esd3D:
 | 
						|
            return ImageDim::THREE;
 | 
						|
        case glslang::TSamplerDim::EsdCube:
 | 
						|
            return ImageDim::CUBE;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    logAndDie("Don't know how to convert Glslang sampler dimensions ...");
 | 
						|
}
 | 
						|
 | 
						|
ShaderVariableType convertGlslangType(const glslang::TType& type)
 | 
						|
{
 | 
						|
    ShaderVariableType result;
 | 
						|
    if (type.isVector())
 | 
						|
    {
 | 
						|
        result.baseType = ShaderVariableBaseType::SIMPLE;
 | 
						|
        result.simple.format = convertGlslangVectorType(type);
 | 
						|
    } else if (type.isMatrix())
 | 
						|
    {
 | 
						|
        result.baseType = ShaderVariableBaseType::MATRIX;
 | 
						|
        result.matrixType = convertGlslangMatrixType(type);
 | 
						|
    } else if (type.isStruct())
 | 
						|
    {
 | 
						|
        const std::size_t numMembers = type.getStruct()->size();
 | 
						|
        result.baseType = ShaderVariableBaseType::STRUCT;
 | 
						|
        result.struct_.members.reserve(numMembers);
 | 
						|
 | 
						|
        std::size_t currentOffset = 0;
 | 
						|
        for (const glslang::TTypeLoc& typeLoc: *type.getStruct())
 | 
						|
        {
 | 
						|
            ShaderVariableStructMember& member = result.struct_.members.emplace_back();
 | 
						|
            member.name = typeLoc.type->getFieldName();
 | 
						|
            member.type = convertGlslangType(*typeLoc.type);
 | 
						|
            member.offset = currentOffset;
 | 
						|
            if (typeLoc.type->getQualifier().hasSemantic())
 | 
						|
            {
 | 
						|
                member.semantic = typeLoc.type->getQualifier().layoutSemantic;
 | 
						|
            }
 | 
						|
            if (typeLoc.type->getQualifier().hasSemanticIndex())
 | 
						|
            {
 | 
						|
                member.semanticIdx = typeLoc.type->getQualifier().layoutSemanticIndex;
 | 
						|
            }
 | 
						|
            currentOffset = member.offset + calcShaderTypeSize(member.type); // TODO: padding
 | 
						|
        }
 | 
						|
 | 
						|
    } else if (type.getBasicType() == glslang::EbtSampler)
 | 
						|
    {
 | 
						|
        const glslang::TSampler& sampler = type.getSampler();
 | 
						|
        result.baseType = ShaderVariableBaseType::IMAGE;
 | 
						|
        result.image.dimensions = convertGlslangSamplerDim(sampler.dim);
 | 
						|
        result.image.format = convertGlslangLayoutFormat(type.getQualifier().layoutFormat);
 | 
						|
    } else
 | 
						|
    {
 | 
						|
        result.baseType = ShaderVariableBaseType::SIMPLE;
 | 
						|
        result.simple.format = convertGlslangBaseType(type);
 | 
						|
    }
 | 
						|
 | 
						|
    if (type.isArray())
 | 
						|
    {
 | 
						|
        if (type.isArrayVariablyIndexed())
 | 
						|
        {
 | 
						|
            result.arraySize = 0;
 | 
						|
            result.dynamicArraySize = true;
 | 
						|
        } else
 | 
						|
        {
 | 
						|
            assert(type.getArraySizes()->getNumDims() == 1); // don't support multi dimensional arrays yet
 | 
						|
            result.arraySize = type.getOuterArraySize();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
vk::DescriptorType getGlslangDescriptorType(const glslang::TType& type)
 | 
						|
{
 | 
						|
    if (type.getBasicType() == glslang::EbtSampler)
 | 
						|
    {
 | 
						|
        if (type.getSampler().combined)
 | 
						|
        {
 | 
						|
            return vk::DescriptorType::eCombinedImageSampler;
 | 
						|
        }
 | 
						|
        if (type.getSampler().isImage())
 | 
						|
        {
 | 
						|
            return vk::DescriptorType::eStorageImage;
 | 
						|
        }
 | 
						|
    } else if (type.isStruct())
 | 
						|
    {
 | 
						|
        if (type.getQualifier().isUniform())
 | 
						|
        {
 | 
						|
            return vk::DescriptorType::eUniformBuffer;
 | 
						|
        }
 | 
						|
        return vk::DescriptorType::eStorageBuffer;
 | 
						|
    }
 | 
						|
    logAndDie("No idea what to do with this type :/");
 | 
						|
}
 | 
						|
 | 
						|
bool MetaCollectingTraverser::visitBinary(glslang::TVisit, glslang::TIntermBinary* node)
 | 
						|
{
 | 
						|
    (void) node;
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
bool MetaCollectingTraverser::visitUnary(glslang::TVisit, glslang::TIntermUnary* node)
 | 
						|
{
 | 
						|
    (void) node;
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
bool MetaCollectingTraverser::visitAggregate(glslang::TVisit, glslang::TIntermAggregate* node)
 | 
						|
{
 | 
						|
    switch (node->getOp())
 | 
						|
    {
 | 
						|
        case glslang::EOpSequence:
 | 
						|
            return true;
 | 
						|
        case glslang::EOpFunction:
 | 
						|
            break;
 | 
						|
        case glslang::EOpLinkerObjects:
 | 
						|
            return true;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
bool MetaCollectingTraverser::visitSelection(glslang::TVisit, glslang::TIntermSelection* node)
 | 
						|
{
 | 
						|
    (void) node;
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
void MetaCollectingTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
 | 
						|
{
 | 
						|
    (void) node;
 | 
						|
}
 | 
						|
 | 
						|
void MetaCollectingTraverser::visitSymbol(glslang::TIntermSymbol* node)
 | 
						|
{
 | 
						|
    const bool isLinkerObject = getParentNode()
 | 
						|
                                && getParentNode()->getAsAggregate()
 | 
						|
                                && getParentNode()->getAsAggregate()->getOp() == glslang::EOpLinkerObjects;
 | 
						|
    if (isLinkerObject)
 | 
						|
    {
 | 
						|
        if (node->getQualifier().builtIn)
 | 
						|
        {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        if (node->getQualifier().isUniformOrBuffer())
 | 
						|
        {
 | 
						|
            if (node->getQualifier().isPushConstant())
 | 
						|
            {
 | 
						|
                ShaderPushConstantBlock pushConstantBlock;
 | 
						|
                pushConstantBlock.type = convertGlslangType(node->getType());
 | 
						|
                assert(pushConstantBlock.type.baseType == ShaderVariableBaseType::STRUCT);
 | 
						|
                meta.extendPushConstant(pushConstantBlock, ShaderTypeBits::make(shaderType));
 | 
						|
                return;
 | 
						|
            }
 | 
						|
            const unsigned setIdx = node->getQualifier().hasSet() ? node->getQualifier().layoutSet : UNSPECIFIED_INDEX;
 | 
						|
            const unsigned binding = node->getQualifier().hasBinding() ? node->getQualifier().layoutBinding : UNSPECIFIED_INDEX;
 | 
						|
            ShaderVariableSet& set = meta.getOrCreateInterfaceVariableSet(setIdx);
 | 
						|
            assert(setIdx == UNSPECIFIED_INDEX || !set.getVariableAtBindingOpt(binding)); // multiple bindings at the same index?
 | 
						|
            set.usedInStages.set(shaderType, true);
 | 
						|
 | 
						|
            ShaderVariable& var = set.variables.emplace_back();
 | 
						|
            var.binding = binding;
 | 
						|
            var.name = node->getName();
 | 
						|
            if (node->getQualifier().hasSemantic())
 | 
						|
            {
 | 
						|
                var.semantic = node->getQualifier().layoutSemantic;
 | 
						|
            }
 | 
						|
            if (node->getQualifier().hasSemanticIndex())
 | 
						|
            {
 | 
						|
                var.semanticIndex = node->getQualifier().layoutSemanticIndex;
 | 
						|
            }
 | 
						|
 | 
						|
            // uniform blocks are identified by the name of their type
 | 
						|
            if (var.name.empty() || var.name.starts_with("anon@"))
 | 
						|
            {
 | 
						|
                const glslang::TString& typeName = node->getType().getTypeName();
 | 
						|
                if (!typeName.empty())
 | 
						|
                {
 | 
						|
                    var.name = typeName;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            var.descriptorType = getGlslangDescriptorType(node->getType());
 | 
						|
            var.type = convertGlslangType(node->getType());
 | 
						|
        }
 | 
						|
        else if (node->getQualifier().storage == glslang::EvqVaryingIn)
 | 
						|
        {
 | 
						|
            ShaderAttribute attribute;
 | 
						|
            attribute.stage = shaderType;
 | 
						|
            attribute.type = convertGlslangType(node->getType());
 | 
						|
            attribute.location = node->getQualifier().hasLocation() ? node->getQualifier().layoutLocation : UNSPECIFIED_INDEX;
 | 
						|
            attribute.name = node->getName();
 | 
						|
            if (node->getQualifier().hasSemantic())
 | 
						|
            {
 | 
						|
                attribute.semantic = node->getQualifier().layoutSemantic;
 | 
						|
            }
 | 
						|
            if (node->getQualifier().hasSemanticIndex())
 | 
						|
            {
 | 
						|
                attribute.semanticIndex = node->getQualifier().layoutSemanticIndex;
 | 
						|
            }
 | 
						|
            meta.addInputAttribute(std::move(attribute));
 | 
						|
        }
 | 
						|
        else if (node->getQualifier().storage == glslang::EvqVaryingOut)
 | 
						|
        {
 | 
						|
            ShaderAttribute attribute;
 | 
						|
            attribute.stage = shaderType;
 | 
						|
            attribute.type = convertGlslangType(node->getType());
 | 
						|
            attribute.location = node->getQualifier().hasLocation() ? node->getQualifier().layoutLocation : UNSPECIFIED_INDEX;
 | 
						|
            attribute.name = node->getName();
 | 
						|
            if (node->getQualifier().hasSemantic())
 | 
						|
            {
 | 
						|
                attribute.semantic = node->getQualifier().layoutSemantic;
 | 
						|
            }
 | 
						|
            if (node->getQualifier().hasSemanticIndex())
 | 
						|
            {
 | 
						|
                attribute.semanticIndex = node->getQualifier().layoutSemanticIndex;
 | 
						|
            }
 | 
						|
            meta.addOutputAttribute(std::move(attribute));
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
bool MetaCollectingTraverser::visitLoop(glslang::TVisit, glslang::TIntermLoop* node)
 | 
						|
{
 | 
						|
    (void) node;
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
bool MetaCollectingTraverser::visitBranch(glslang::TVisit, glslang::TIntermBranch* node)
 | 
						|
{
 | 
						|
    (void) node;
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
bool MetaCollectingTraverser::visitSwitch(glslang::TVisit, glslang::TIntermSwitch* node)
 | 
						|
{
 | 
						|
    (void) node;
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
vk::ShaderStageFlagBits shaderStageFromGlslang(EShLanguage language)
 | 
						|
{
 | 
						|
    switch (language)
 | 
						|
    {
 | 
						|
        case EShLangVertex:
 | 
						|
            return vk::ShaderStageFlagBits::eVertex;
 | 
						|
        case EShLangTessControl:
 | 
						|
            return vk::ShaderStageFlagBits::eTessellationControl;
 | 
						|
        case EShLangTessEvaluation:
 | 
						|
            return vk::ShaderStageFlagBits::eTessellationEvaluation;
 | 
						|
        case EShLangGeometry:
 | 
						|
            return vk::ShaderStageFlagBits::eGeometry;
 | 
						|
        case EShLangFragment:
 | 
						|
            return vk::ShaderStageFlagBits::eFragment;
 | 
						|
        case EShLangCompute:
 | 
						|
            return vk::ShaderStageFlagBits::eCompute;
 | 
						|
        case EShLangRayGen:
 | 
						|
            return vk::ShaderStageFlagBits::eRaygenKHR;
 | 
						|
        case EShLangIntersect:
 | 
						|
            return vk::ShaderStageFlagBits::eIntersectionKHR;
 | 
						|
        case EShLangAnyHit:
 | 
						|
            return vk::ShaderStageFlagBits::eAnyHitKHR;
 | 
						|
        case EShLangClosestHit:
 | 
						|
            return vk::ShaderStageFlagBits::eClosestHitKHR;
 | 
						|
        case EShLangMiss:
 | 
						|
            return vk::ShaderStageFlagBits::eMissKHR;
 | 
						|
        case EShLangCallable:
 | 
						|
            return vk::ShaderStageFlagBits::eCallableKHR;
 | 
						|
        case EShLangTask:
 | 
						|
            return vk::ShaderStageFlagBits::eTaskEXT;
 | 
						|
        case EShLangMesh:
 | 
						|
            return vk::ShaderStageFlagBits::eMeshEXT;
 | 
						|
        case EShLangCount:
 | 
						|
            break; // fall through
 | 
						|
    }
 | 
						|
    logAndDie("Invalid value passed to shaderStageFromGlslang!");
 | 
						|
}
 | 
						|
}
 | 
						|
 | 
						|
ShaderMeta reflectShader(glslang::TShader& shader)
 | 
						|
{
 | 
						|
    return reflectIntermediate(*shader.getIntermediate(), shaderStageFromGlslang(shader.getStage()));
 | 
						|
}
 | 
						|
 | 
						|
ShaderMeta reflectProgram(glslang::TProgram& program)
 | 
						|
{
 | 
						|
    ShaderMeta result;
 | 
						|
    for (int stage = 0; stage < EShLangCount; ++stage)
 | 
						|
    {
 | 
						|
        glslang::TIntermediate* intermediate = program.getIntermediate(static_cast<EShLanguage>(stage));
 | 
						|
        if (intermediate == nullptr) {
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
        result.extend(reflectIntermediate(*intermediate, shaderStageFromGlslang(static_cast<EShLanguage>(stage))));
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
ShaderMeta reflectIntermediate(glslang::TIntermediate& intermediate, vk::ShaderStageFlagBits stage)
 | 
						|
{
 | 
						|
    ShaderMeta meta;
 | 
						|
    MetaCollectingTraverser traverser(meta, stage);
 | 
						|
    intermediate.getTreeRoot()->traverse(&traverser);
 | 
						|
 | 
						|
    meta.stages.set(stage, true);
 | 
						|
    
 | 
						|
    if (stage == vk::ShaderStageFlagBits::eCompute)
 | 
						|
    {
 | 
						|
        meta.localSizeX = static_cast<unsigned>(intermediate.getLocalSize(0));
 | 
						|
        meta.localSizeY = static_cast<unsigned>(intermediate.getLocalSize(1));
 | 
						|
        meta.localSizeZ = static_cast<unsigned>(intermediate.getLocalSize(2));
 | 
						|
    }
 | 
						|
 | 
						|
    return meta;
 | 
						|
}
 | 
						|
} // namespace iwa
 |