0
$\begingroup$

I'm using shaderc to compile glsl code in to spirv module and pass to pipelie in REAL-TIME. I want to use #include to reuse some of the shader code but shaderc is having problems recognizing it. Any one know how to solve this? (I'm NOT using command line to compile shader upfront.)

The error I got from shaderc is:

standard.vert:6: error: '#include' : #error unexpected include directive for header name: GlobalInclude.glsl

Here are my shaders and client codes:

standard.vert

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

#include "GlobalInclude.glsl"

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTexCoord;

layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord;

void main() {
  gl_Position = passUBO.proj * passUBO.view * objectUBO.model * vec4(inPosition, 1.0);
  fragColor = inColor;
  fragTexCoord = inTexCoord;
}

standard.frag

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

#include "GlobalInclude.glsl"

layout(set = PASS_SET, binding = TEXTURE_SLOT(0)) uniform sampler2D texSamplerAlbedo;

layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord;

layout(location = 0) out vec4 outColor;

void main() {
  //outColor = vec4(fragTexCoord, 0.0, 1.0);
  outColor = texture(texSamplerAlbedo, fragTexCoord);
}

GlobalInclude.glsl

#define FRAME_SET 0//per frame
#define SCENE_SET 1//per scene
#define PASS_SET 2//per pass
#define OBJECT_SET 3//per draw call

#define UNIFORM_BUFFER_BINDING_START 0
#define TEXTURE_BINDING_START 1

#define TEXTURE_SLOT(NUMBER) TEXTURE_BINDING_START + NUMBER

layout(set = SCENE_SET, binding = UNIFORM_BUFFER_BINDING_START + 0) uniform SceneUniformBufferObject {
  uint time;
} sceneUBO;

layout(set = PASS_SET, binding = UNIFORM_BUFFER_BINDING_START + 0) uniform PassUniformBufferObject {
  mat4 proj;
  mat4 view;
  uint passNum;
} passUBO;

layout(set = OBJECT_SET, binding = UNIFORM_BUFFER_BINDING_START + 0) uniform ObjectUniformBufferObject {
  mat4 model;
} objectUBO;

layout(set = FRAME_SET, binding = UNIFORM_BUFFER_BINDING_START + 0) uniform FrameUniformBufferObject {
  uint frameNum;
} frameUBO;

Compile shader using shaderc API:

bool Shader::CreateShaderFromFile(shaderc_shader_kind kind, bool optimize)
{
  // read shader string
  if (!ReadShaderFromFile())
      return false;

  shaderc::Compiler compiler;
  shaderc::CompileOptions options;

  // like -DMY_DEFINE=1
  //options.AddMacroDefinition("MY_DEFINE", "1");
  if (optimize) options.SetOptimizationLevel(shaderc_optimization_level_size);

  std::cout << "output 1:" << shaderString << std::endl;

  // preprocess
  shaderc::PreprocessedSourceCompilationResult preprocessed = compiler.PreprocessGlsl(shaderString, kind, fileName.c_str(), options);

  if (preprocessed.GetCompilationStatus() != shaderc_compilation_status_success) 
  {
      throw std::runtime_error(preprocessed.GetErrorMessage());
      return false;
  }

  shaderString = { preprocessed.cbegin(), preprocessed.cend() };

  std::cout << "output 2:" << shaderString << std::endl;

  // compile
  shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv(shaderString, kind, fileName.c_str(), options);

  if (module.GetCompilationStatus() != shaderc_compilation_status_success)
  {
      throw std::runtime_error(module.GetErrorMessage());
      return false;
  }

  shaderBytecode = { module.cbegin(), module.cend() };// not sure why sample code copy vector like this

  return true;
}
$\endgroup$

2 Answers 2

4
$\begingroup$

It is your responsibility to support includes by instantiating an IncluderInterface instance and calling SetIncluder(...) on the options instance.

The interface includer API consists of the following methods:

// Handles shaderc_include_resolver_fn callbacks.
virtual shaderc_include_result* GetInclude(const char* requested_source,
                                           shaderc_include_type type,
                                           const char* requesting_source,
                                           size_t include_depth) = 0;

// Handles shaderc_include_result_release_fn callbacks.
virtual void ReleaseInclude(shaderc_include_result* data) = 0;

It will therefore also be your responsibility to implement these functions and interpret the #include directives from the GLSL into shaderc_include_result instances that will be used by shaderc to complete the preprocessing of the GLSL.

$\endgroup$
2
  • $\begingroup$ Thanks! Solved it with FileIncluder from shaderc/glslc/src/file_includer.h and shaderc/glslc/src/file_includer.cc $\endgroup$
    – ACskyline
    Jun 14, 2019 at 2:22
  • $\begingroup$ @ACskyline did you have to do anything other than implementing the interface? Did you have to call something to trigger a preprocessor? I am trying to do this same thing but gslc is not replacing the include with the body of the included file. $\endgroup$
    – Makogan
    May 5, 2021 at 1:55
0
$\begingroup$

I was able to solve the #include issue by linking both the shaderc/glslc and shaderc/shaderc_util libraries and using file_includer.h and file_finder.h as suggested in a comment by ACskyline.

  #include <shaderc/glslc/src/file_includer.h>
  #include <shaderc/libshaderc_util/include/libshaderc_util/file_finder.h>

  // [...]
  
  // somewhere before using the compiler
  shaderc_util::FileFinder fileFinder;
  options.SetIncluder(std::make_unique<glslc::FileIncluder>(&fileFinder));
```
$\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.