c++glslshadervulkan

shaderc IncluderInterface, include fails?


I am trying to support #include directives for glsl in a Vulkan project.

To my understanding all that is required is to properly implement the IncluderInterface and set it, which I did like this:

class NEShaderIncluder : public CompileOptions::IncluderInterface
{
    shaderc_include_result* GetInclude(
        const char* requested_source,
        shaderc_include_type type,
        const char* requesting_source,
        size_t include_depth)
    {
        cout << requested_source << endl;
        cout << to_string(type) << endl;
        cout << requesting_source << endl;
        cout << include_depth << endl;

        const string name = string(requested_source);
        const string contents = ReadFile(name);

        auto container = new std::array<std::string, 2>;
        (*container)[0] = name;
        (*container)[1] = contents;

        auto data = new shaderc_include_result;

        data->user_data = container;

        data->source_name = (*container)[0].data();
        data->source_name_length = (*container)[0].size();

        data->content = (*container)[1].data();
        data->content_length = (*container)[1].size();

        cout << "!!!!!!!!!!!!!!!!!!!" << endl;

        cout << data->content << endl;

        return data;
    };

    void ReleaseInclude(shaderc_include_result* data) override
    {
        delete static_cast<std::array<std::string, 2>*>(data->user_data);
        delete data;
    };
};

CompileOptions SetShaderCompilationOptions()
{
    CompileOptions options;
    options.SetIncluder(std::make_unique<NEShaderIncluder>());
    options.SetGenerateDebugInfo();
    return options;
}

And then I compile my shaders like this:

    Compiler compiler;
    CompileOptions options = SetShaderCompilationOptions();
    shaderc::SpvCompilationResult result =
        compiler.CompileGlslToSpv(source, shader_type, shader_name.c_str(), options);

All the print statements I added to that function work and print what I expect, for example this is the last print:

vec4 BlinnPhong(vec3 pos, vec3 normal, vec3 camera_position)
{
    vec4 color = vec4(0);
    vec3 l = vec3(1);

    vec3 c = vec3(0, 0, 0.7);
    vec3 n = normalize(normal);
    vec3 e = camera_position - pos;
    e = normalize(e);
    vec3 h = normalize(e + l);

    color = vec4(
        c * (vec3(0.1) + 0.9 * max(0, dot(n, l))) +
            vec3(0.9) * max(0, pow(dot(h, n), 100)),
        1);

    return color;
}

However, shaderc doesn’t seem to be replacing the include, I get this as an error message from the result object:

#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_GOOGLE_include_directive : require

#include "shaders/Example2/phong_lighting.glsl"

layout(location = 0) out vec4 color_out;

layout(location = 0) in vec3 position;
layout(location = 1) in vec2 tex_coord;
layout(location = 2) in vec3 normal;

layout(binding = 1) uniform CameraInfo {
    vec3 camera_position;
};

void main()
{
    color_out = BlinnPhong(position, normal);
}:
fragment_shader:19: error: 'BlinnPhong' : no matching overloaded function found
fragment_shader:19: error: 'assign' :  cannot convert from ' const float' to 'layout( location=0) out highp 4-component vector of float'

I am not entirely sure what is wrong with my use of the API, and I have not been able to find examples online to cross reference.

I suspect one must call PreprocessGlsl beforehand but I am not sure how you are supposed to chain preprocessing and compilation.


Solution

  • The problem is that you are supposed to call a preprocessing stage in addition to setting up the include, the correct call site looks like this:

        shaderc::PreprocessedSourceCompilationResult pre_result =
            compiler.PreprocessGlsl(source, shader_type, shader_name.c_str(), options);
        Assert(
            pre_result.GetCompilationStatus() == shaderc_compilation_status_success,
            "Preprocess failed for file " + source + ":\n" + pre_result.GetErrorMessage());
    
        string pre_passed_source(pre_result.begin());
    
        shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(
            pre_passed_source, shader_type, shader_name.c_str(), options);
        Assert(
            result.GetCompilationStatus() == shaderc_compilation_status_success,
            pre_passed_source + ":\n" + result.GetErrorMessage());