oryol icon indicating copy to clipboard operation
oryol copied to clipboard

oryol_shader:how to compile the generated shader into lib?

Open jerett opened this issue 6 years ago • 7 comments

When I write a render lib based on oryol, shader is also included in the lib, and the generated shader is also included in the lib project. The other project can't use the generated shader because the generated shader header is not avaliable to the third app.

jerett avatar Nov 08 '17 03:11 jerett

Yes, this is sort-of by design because of hard-to-debug include collision when the generated shader headers are named identically, so the generated sources are created "out of source" in the fips-build directory, and the header search path to this location is only valid for the project of that file.

You should be able to fix this in your lib project though with a new variant of the oryol_shader() cmake macro (see here: https://github.com/floooh/oryol/blob/095e81a8a8e977b20f70db33b540ebd510a7fe72/fips-include.cmake#L195)

It would work like this:

  • in your lib project's root dir, create a file fips-include.cmake
  • copy the original oryol_shader macro there, but rename it to something else
  • remove the OUT_OF_SOURCE parameter from the call to fips_generate()
  • finally replace the calls to oryol_shader() in your own lib with your own macro
  • run ./fips clean + ./fips gen etc...

This will now place the generated files "in source" into the same directory where the shaders.shd file is, and this should be visible to external libraries, you need to make sure that the generated file names don't collide with other headers in the include search path though. The downside is however, that a whole bunch of other generated files will also be dumped there (all the intermediate shader source code and SPIRV-Files), so you'd probably want to add those to your .gitignore file (fixing this would require changes to the shader code generator python scripts in the Oryol project itself).

If this isn't acceptable for your use case the other option would be to have some sort of wrapper C++ API to access the generated ShaderSetup objects from outside your lib (almost sounds like the better solution to me, since it would eliminate the header-collision problem).

Let me know how this works for you.

PS: In general I want to have the shader/uniformblock-related API in the Gfx module a bit more "dynamic" in the future to aid more dynamic material systems. This probably includes exposing some sort of reflection information from the shader generation pass into the C++ code, and a more flexible version of Gfx::ApplyUniformBlock().

floooh avatar Nov 08 '17 04:11 floooh

...on second thought, maybe the "wrapper API" solution won't work, because the code which actually uses the shaders must indeed include the generated header files. Some sort of forward-declaration won't work.

So I guess you're limited to the "in source tree" code generation for now.

floooh avatar Nov 08 '17 04:11 floooh

for the first solution, if I want to generate OpenGL shader on window, and metal shader on iOS, will lead to source code conflict?

jerett avatar Nov 08 '17 07:11 jerett

Ahh, yes you're right the generated header/source pair will be different on each platform, I think it's best if they go into a local .gitignore too.

But I just found another problem: switching between different build configs will not rebuild the shaders because the files are not detected as "dirty" :/

Wait a sec I'm trying something else...

floooh avatar Nov 08 '17 08:11 floooh

...ok here's a better solution, the idea is to export an additional header search directory from your shader library project.

  • first undo all the stuff describes above with the custom cmake macro
  • then in the CMakeLists.txt file of your shader library module, add a target_include_directories() statement with PUBLIC visibility, this will inject the right header search path into "upstream projects"

Here's an example that I just tried out, let's say I want to "export" the shader of Oryol's Dbg module, I modified the CMakeLists.txt file of the Dbg module (https://github.com/floooh/oryol/blob/master/code/Modules/Dbg/CMakeLists.txt, just add a line to the end):

fips_begin_module(Dbg)
    fips_vs_warning_level(3)
    fips_files(Dbg.cc Dbg.h)
    fips_dir(private)
    fips_files(debugFont.cc debugTextRenderer.cc debugTextRenderer.h)
    oryol_shader(DebugShaders.glsl)
    fips_deps(Core Gfx)
fips_end_module()
target_include_directories(Dbg PUBLIC "${FIPS_PROJECT_BUILD_DIR}/oryol_Dbg")

Note the target_include_directories() args, each is important :)

The Dbg is the name of the module (in your case the shader library module).

The PUBLIC is necessary so that the header path isn't only visible to this module.

${FIPS_PROJECT_BUILD_DIR}/oryol_Dbg: The FIPS_PROJECT_BUILD_DIR is resolved to the current build directory under fips-build/[proj_name]/[config_name]. The oryol_Dbg is the file filename convention for imported modules, the first name oryol is the name of the imported project, and the Dbg is the name of the imported module.

In project which use the shader library module as dependency, it should be enough to do a fips clean+fips_gen now, and you can check in the Visual Studio or Xcode properties window if the new header path is there (I just tried this in Xcode, and it seems to work).

Good luck, and let me know how it goes :)

floooh avatar Nov 08 '17 08:11 floooh

The later solution works fine, thank you!

jerett avatar Nov 09 '17 10:11 jerett

FYI I'll reopen the ticket as a FAQ, if others have the same problem :)

floooh avatar Nov 09 '17 10:11 floooh