KhronosGroup / glslang

Khronos-reference front end for GLSL/ESSL, partial front end for HLSL, and a SPIR-V generator.
Other
2.98k stars 823 forks source link

API generates invalid SPIRV #3251

Open LtJulius opened 1 year ago

LtJulius commented 1 year ago

I was trying to generate SPIRV (Vulkan 1.3, Spv 1.6) by using the c++ api, but got the following errors:

1st operand of Capability: operand RayTraversalPrimitiveCullingKHR(4478) requires one of these extensions: SPV_KHR_ray_query SPV_KHR_ray_tracing 
  OpCapability RayTraversalPrimitiveCullingKHR

Here is the related glsl test code.

#version 450

void main() {
    gl_Position = vec4(vec3(0.0), 1.0);
}

And some "printouts" of the used objects

TShader Environment
{input={languageFamily=EShSourceGlsl (1) stage=EShLangVertex (0) dialect=EShClientVulkan (1) ...} client=...}
    input: {languageFamily=EShSourceGlsl (1) stage=EShLangVertex (0) dialect=EShClientVulkan (1) ...}
    client: {client=EShClientVulkan (1) version=EShTargetVulkan_1_3 (4206592) }
    target: {language=EShTargetSpv (1) version=EShTargetSpv_1_6 (67072) hlslFunctionality1=false }

TIIntermediate
{language=EShLangVertex (0) entryPoint Name="main" entryPointMangledName="main(" ...}
    language: EShLangVertex (0)
    entryPointName: "main"
    entryPointMangledName: "main("
    callGraph: { size=0 }
    profile: ECoreProfile (2)
    version: 450
    spvVersion: {spv=67072 vulkanGlsl=100 vulkan=4206592 ...}
    treeRoot: 0x000002d2f6c20498 {sequence={ size=2 } qualifier={ size=0 } name="" ...}
    requestedExtensions: { size=0 }
    resources: {value={maxLights=0 maxClipPlanes=0 maxTextureUnits=0 ...} isSet=true }
    numEntryPoints: 1
    numErrors: 0
    numPushConstants: 0
   ...

The problem is, I can't replicate the error by using the glslangValidator to transpile the same source code.

arcady-lunarg commented 1 year ago

Could you attach the code you were using to generate this SPIR-V?

LtJulius commented 1 year ago

Yeah, sorry.

#include "SpirvCompiler.hpp"

#include <Engine.Common/Make.hpp>
#include <Engine.Common/Wrapper.hpp>
#include <Engine.Logging/Logger.hpp>

// glslang includes
//#include <glslang/Public/ShaderLang.h>
#include <glslang/Public/ResourceLimits.h>
#include <glslang/SPIRV/GlslangToSpv.h>

// spirv includes
//#include <spirv-tools/libspirv.hpp>
//#include <spirv-tools/linker.hpp>
//#include <spirv-tools/optimizer.hpp>

using namespace hg::engine::gfx::acc;
using namespace hg;

_STD atomic_uint_fast32_t hg::engine::gfx::acc::extern_compiler_ref_count { 0ui32 };

/**/

SpirvCompiler::SpirvCompiler() :
    _srcLang(SpirvSrcLang::eGlsl),
    _dialect(SpirvDialect::eVulkan),
    _targetClient(SpirvTargetClient::eVulkan13),
    _targetVersion(SpirvTargetVersion::eSpv16) {
    if (extern_compiler_ref_count.fetch_add(1ui32) == 0) {
        //ShInitialize();
        glslang::InitializeProcess();
    }
}

SpirvCompiler::~SpirvCompiler() {
    if (extern_compiler_ref_count.fetch_sub(1ui32) == 1ui32) {
        //ShFinalize();
        glslang::FinalizeProcess();
    }
}

SpirvByteCode SpirvCompiler::compile(cref<ModuleSource> module_, cref<Vector<string>> source_) const {

    const auto targetStage = static_cast<_STD underlying_type_t<ModuleTargetStage>>(module_.targetStage) - 1;
    assert(targetStage >= 0 && targetStage < EShLanguageMaskCount);

    EShLanguage stage { reinterpret_cast<cref<EShLanguage>>(targetStage) };
    bool status = true;

    /**/

    uptr<glslang::TProgram> glslProgram = make_uptr<glslang::TProgram>();
    uptr<glslang::TShader> glslShader = make_uptr<glslang::TShader>(stage);

    glslProgram->addShader(glslShader.get());

    /**/

    s32 langVersion { 100 /* EShClientVulkan, 100 => SPIR-V */ };

    glslShader->setEnvClient(
        reinterpret_cast<cref<glslang::EShClient>>(_dialect),
        reinterpret_cast<cref<glslang::EShTargetClientVersion>>(_targetClient)
    );
    glslShader->setEnvInput(
        reinterpret_cast<cref<glslang::EShSource>>(_srcLang),
        stage,
        reinterpret_cast<cref<glslang::EShClient>>(_dialect),
        langVersion
    );
    glslShader->setEnvTarget(
        glslang::EShTargetLanguage::EShTargetSpv,
        reinterpret_cast<cref<glslang::EShTargetLanguageVersion>>(_targetVersion)
    );

    Vector<ptr<const char>> codeSnippets {};
    Vector<s32> codeSnippetLength {};

    codeSnippets.reserve(source_.size());
    codeSnippetLength.reserve(source_.size());

    for (u32 i = 0; i < source_.size(); ++i) {
        codeSnippets.push_back(source_[i].data());
        codeSnippetLength.push_back(static_cast<s32>(source_[i].size()));
    }

    glslShader->setStringsWithLengths(codeSnippets.data(), codeSnippetLength.data(), static_cast<s32>(source_.size()));

    /**/

    s32 defaultVersion { 110 };
    EShMessages msg { EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules };

    glslShader->setDebugInfo(true);

    status = glslShader->parse(GetResources(), defaultVersion, false, msg);

    if (not status) {
        IM_CORE_WARN(glslShader->getInfoLog());
        IM_CORE_WARN(glslShader->getInfoDebugLog());
    }

    /**/

    if (status) {
        status = glslProgram->link(msg);
    }

    /**/

    SpirvByteCode byteCode {};

    if (status) {

        const auto* const intermediate = glslProgram->getIntermediate(stage);
        glslang::SpvOptions spvOpts {
            .validate = true
        };
        spv::SpvBuildLogger spvLog {};

        glslang::GlslangToSpv(*intermediate, reinterpret_cast<ref<Vector<u32>>>(byteCode), &spvLog, &spvOpts);

        status = not spvLog.errors.empty();
    }

    if (not status) {
        byteCode.clear();
    }

    /**/

    glslProgram.reset();
    glslShader.reset();

    /**/

    return byteCode;
}
; SPIR-V
; Version: 1.6
; Generator: Khronos Glslang Reference Front End; 11
; Bound: 21
; Schema: 0
               OpCapability Shader
               OpCapability RayTraversalPrimitiveCullingKHR
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Vertex %4 "main" %13
               OpMemberDecorate %_struct_11 0 BuiltIn Position
               OpMemberDecorate %_struct_11 1 BuiltIn PointSize
               OpMemberDecorate %_struct_11 2 BuiltIn ClipDistance
               OpMemberDecorate %_struct_11 3 BuiltIn CullDistance
               OpDecorate %_struct_11 Block
       %void = OpTypeVoid
          %3 = OpTypeFunction %void
      %float = OpTypeFloat 32
    %v4float = OpTypeVector %float 4
       %uint = OpTypeInt 32 0
     %uint_1 = OpConstant %uint 1
%_arr_float_uint_1 = OpTypeArray %float %uint_1
 %_struct_11 = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
%_ptr_Output__struct_11 = OpTypePointer Output %_struct_11
         %13 = OpVariable %_ptr_Output__struct_11 Output
        %int = OpTypeInt 32 1
      %int_0 = OpConstant %int 0
    %float_0 = OpConstant %float 0
    %float_1 = OpConstant %float 1
         %18 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
%_ptr_Output_v4float = OpTypePointer Output %v4float
          %4 = OpFunction %void None %3
          %5 = OpLabel
         %20 = OpAccessChain %_ptr_Output_v4float %13 %int_0
               OpStore %20 %18
               OpReturn
               OpFunctionEnd

Therefore I guess: https://github.com/KhronosGroup/glslang/blob/main/SPIRV/GlslangToSpv.cpp#L1655C36-L1655C77

If you need it, I can try to make a stripped down version of it.

LtJulius commented 1 year ago

This seams only to happen, when I use the provided binaries of main-tot or distributed binaries of vulkan sdk. Using the "manually" compiled libraries to link seams to work just fine.