5
$\begingroup$

I'm making a cross-platform application, and i need my shaders to be compiled to SPIR-V for both Opengl and Vulkan. It seems that the only way to do so is to call a separate program, called "glslangValidator.exe/.deb/.dmg". This sort of makes it cross-platform, but it requires me to change the command that calls the program on each platform (and that's not ideal to me). Can i embed some code or use something else to compile shaders directly from my application?

$\endgroup$
1
  • $\begingroup$ Be advised that, in some cases, the same construct in GLSL can mean subtly different things in OpenGL and Vulkan. Not to mention the differences in layout qualifiers for resource binding. $\endgroup$ Oct 2, 2018 at 20:10

2 Answers 2

7
$\begingroup$

Typically compiling GLSL to SPIRV would be something you do as part of the build process, so that you end up distributing SPIRV instead of GLSL. Then you don't need to compile it at runtime. Assuming you're using the Vulkan SDK, the binary for glslangValidator (or a shell script to build it) should be part of the installed SDK.

That said, if you want to compile GLSL to SPIRV at runtime, you can link against the glslang library and do that. Take a look at the Programatic Interface section in the readme.

$\endgroup$
1
$\begingroup$

The new C interface for glslang is coming.

https://github.com/KhronosGroup/glslang/pull/2038

Here is a way how to use it:

const char* shaderCodeVertex = ...;

const glslang_input_t input =
{
    .language = GLSLANG_SOURCE_GLSL,
    .stage = GLSLANG_STAGE_VERTEX,
    .client = GLSLANG_CLIENT_VULKAN,
    .client_version = GLSLANG_TARGET_VULKAN_1_1,
    .target_language = GLSLANG_TARGET_SPV,
    .target_language_version = GLSLANG_TARGET_SPV_1_3,
    .code = shaderCodeVertex,
    .default_version = 100,
    .default_profile = GLSLANG_NO_PROFILE,
    .force_default_version_and_profile = false,
    .forward_compatible = false,
    .messages = GLSLANG_MSG_DEFAULT_BIT,
};

glslang_initialize_process();

glslang_shader_t* shader = glslang_shader_create( &input );

if ( !glslang_shader_preprocess(shader, &input) )
{
    // use glslang_shader_get_info_log() and glslang_shader_get_info_debug_log()
}

if ( !glslang_shader_parse(shader, &input) )
{
    // use glslang_shader_get_info_log() and glslang_shader_get_info_debug_log()
}

glslang_program_t* program = glslang_program_create();
glslang_program_add_shader( program, shader );

if (!glslang_program_link(program, GLSLANG_MSG_SPV_RULES_BIT | GLSLANG_MSG_VULKAN_RULES_BIT))
{
    // use glslang_program_get_info_log() and glslang_program_get_info_debug_log();
}

glslang_program_SPIRV_generate( program, input.stage );

if ( glslang_program_SPIRV_get_messages(program) )
{
    printf("%s", glslang_program_SPIRV_get_messages(program));
}

glslang_shader_delete( shader );

const VkShaderModuleCreateInfo ci =
{
    .sType    = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
    .codeSize = glslang_program_SPIRV_get_size(program) * sizeof(unsigned int),
    .pCode    = glslang_program_SPIRV_get_ptr(program)
};

VkResult result = vkCreateShaderModule(device, &ci, nullptr, ...);

glslang_program_delete( program );
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.