Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make runtime shader compilation optional #251

Open
wants to merge 39 commits into
base: master
Choose a base branch
from

Conversation

bullno1
Copy link
Contributor

@bullno1 bullno1 commented Nov 22, 2024

Huge changes:

  • Add libcute-shader as a wrapper for glslang.
  • Add cute-shaderc, an offline compiler that can generate header for embedding.
  • Add various functions to accept bytecode from generated headers.
  • Precompile builtin shaders and also allow runtime compilation.
    Builtin shaders have to be declared in src/cute_shader/builtin_shaders.h
  • Updated all samples to support both precompiled bytecode and runtime compilation.

As of this writing, windows build in CI is blocked by: actions/runner-images#10978.

Allso, #include within the cf_shader_directory is not yet resolved. (Implemented)
I'm posting this early for feedbacks.

Copy link
Owner

@RandyGaul RandyGaul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Questions:

  • Is the shader compiler a standalone program? Which source is it exactly? I didn't want to spend time trawling the cmake file to find out. Is it just cute_shaderc.cpp and associated header?
  • Could you outline here what the major individual build targets are exactly and outline their dependencies to each other?
  • Can the shader compiler be linked in statically into cute.lib or cute.dll (static or dynamic libs, but not as a standalone exe), as a simple cmake option?
  • Is this easy for users to toggle on/off in cmake? I want runtime shaders in CF on by default, and behind a single cmake option to turn them off and NOT compile or pull in any SPIRV nonsense. Is that the way things work here as of now?
  • Do you have plans yet to add in a dedicated website page for documenting the compiler?
  • Can the compiler output serialized SPIRV blobs directly, and not just C headers?
  • Can the compiler output reflection info required for passing into SDL_Gpu (various input counts for specific resource sets)?
  • I'd prefer only one or two samples to use bytecode. The rest should just use runtime shaders alone to reduce complexity.

CMakeLists.txt Outdated
add_executable(timestep samples/timestep.cpp)
add_executable(joypad samples/joypad.c)
add_executable(outline_stencil samples/outline_stencil.cpp)
add_executable(recolor samples/recolor.cpp)
add_executable(recolor samples/recolor.cpp samples/recolor_data/recolor_shd.h)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer the majority of sample code to use runtime string shaders. Precompiling is unneeded complexity when starting out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I made the changes just to check that all samples are fine with CF_GLSLANG=OFF

I can revert but those samples would crash when CF_GLSLANG=OFF, is that acceptable?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that's fine. As long as they all work with default settings when cloning, if the user turns it off I would expect them to then crash.

* @remarks This can be created using the `cute-shaderc` compiler.
* @related CF_Shader cf_draw_push_shader cf_draw_pop_shader cf_draw_peek_shader cf_make_draw_shader_from_bytecode
*/
typedef struct CF_DrawShaderBytecode {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline on brace to match the rest of CF. We will need a page on CF website documenting cute-shaderc for sure. I can help get you going on that if you need -- it's really easy.

@@ -0,0 +1,36 @@
#pragma once

static const uint8_t s_tri_fs_bytecode_content[448] = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want, in a comment, the string representation of the shader just above the bytecode here. Perhaps the compiler should output this directly into the header. sokol-shdc does this and it's greatly appreciated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Preprocessed shader or original code?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably preprocessed

size_t size;
};

class Includer: public glslang::TShader::Includer {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, is this includer thing a part of the glslang API? I hate it, but looks like it's just a way to use glslang, which is accpetable and I'm glad you hid this all back here in the implementation in an isolated place.

Copy link
Contributor Author

@bullno1 bullno1 Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is glslang API to search for include file. It is passed to glslang:TShader::preprocess. glslang will call the includer to search for files.

I use that to implement lookup in the VFS, builtin shader include and also automatic include guard.

In the case of duplicated includes, the content is resolved into an empty string.

@RandyGaul
Copy link
Owner

Would also be quite nice to document in the code as comment a rough plan on transitioning to SDL shader tools in the future, explaining how the current SPIRV handling is temporary until SDL evolves more thoroughly.

@bullno1
Copy link
Contributor Author

bullno1 commented Nov 23, 2024

Is the shader compiler a standalone program? Which source is it exactly? I didn't want to spend time trawling the cmake file to find out. Is it just cute_shaderc.cpp and associated header?

Yes, it is just src/cute_shader/cute_shaderc.cpp.

Could you outline here what the major individual build targets are exactly and outline their dependencies to each other?

First, all glslang and spriv targets are now unconditionally fetched.

cute-shader is a library that wraps glslang compilation into spirv.
It depends on glslang.

cute-shaderc is a CLI program that can compile glsl to spriv and generate a C header.
It depends on cute-shader.
Notably it is also used to generate src/data/builtin_shaders_bytecode.h with the -type=builtin flag.
Mostly because I didn't want to make another program just for that.
This is done through a add_custom_command so whenever src/cute_shader/builtin_shaders.h is edited, cute-shaderc will get rebuilt and the bytecode header will be regenerated, keeping it in sync.

cute itself always depend on SPIRV tools since it still needs to do reflection even without runtime compilation.
The cute-shader dependency is conditional.

When CF_GLSLANG=OFF it will not link to cute-shader.
All compilation functions just return NULL.
Samples using inline string shader will crash (with a message in stderr).

When CF_GLSLANG=ON it will link to cute-shader.
All compilation functions will call cute_shader_compile.
Include now works with VFS and it will search in the cf_shader_directory if set.
The directory is passed to cute-shader as an include directory, similar to the -I flag in cute-shaderc.

Can the shader compiler be linked in statically into cute.lib or cute.dll (static or dynamic libs, but not as a standalone exe), as a simple cmake option?

Yes. It is the CF_GLSLANG option.

Is this easy for users to toggle on/off in cmake? I want runtime shaders in CF on by default, and behind a single cmake option to turn them off and NOT compile or pull in any SPIRV nonsense. Is that the way things work here as of now?

Not quite yet.
glslang is always pulled because the shader compiler requires that.
I can make it so that cute-shaderc is not built.
Then when CF_GLSLANG=OFF and CF_CUTE_SHADERC=OFF, glslang will not be pulled.

SPIRV-tool is still needed regardless of options because I have only implemented bytecode compilation, not reflection.
I plan to do that next.

Do you have plans yet to add in a dedicated website page for documenting the compiler?

Yes, I can do that.

Can the compiler output serialized SPIRV blobs directly, and not just C headers?

It was possible earlier but I reverted it because draw shader, the most common case, is a couple of shaders.
This can be added back and it will error on cases other than -type=vertex or -type=fragment.
The other values are:

  • draw: Draw shader, which is actually 2 fragment shaders.
  • builtin: Dump all builtin shaders, for when runtime compilation is turned off.

I can add a -obytecode= flag.

Can the compiler output reflection info required for passing into SDL_Gpu (various input counts for specific resource sets)?

Not yet.
That should be next in the list.
This will truly get rid of SPIRV and co from cute with CF_GLSLANG=OFF.
With CF_CUTE_SHADERC=OFF they will not even be pulled.

Is the plan to distribute cute-shaderc as a prebuilt binary to save users from the pain?

I'd prefer only one or two samples to use bytecode. The rest should just use runtime shaders alone to reduce complexity.

Sure. I will only make changes to samples that already use shader in file and revert changes from samples with inline shaders.

@bullno1
Copy link
Contributor Author

bullno1 commented Nov 23, 2024

Would also be quite nice to document in the code as comment a rough plan on transitioning to SDL shader tools in the future, explaining how the current SPIRV handling is temporary until SDL evolves more thoroughly.

Tbh, I have no idea where SDL shader tool is heading.
This is my reference: https://github.com/libsdl-org/SDL_shader_tools.

I'll add some comment on how it is a temporary solution.
But I think what we can somewhat guarantee is that the API will remain the same.
That includes the compiler and all its flags, the include behaviour etc...

Shader syntax may change depending on what SDL_shader tool is doing.

@RandyGaul
Copy link
Owner

RandyGaul commented Nov 23, 2024

But I think what we can somewhat guarantee is that the API will remain the same.

Thanks! Excellent.

Edit: I'll get to the rest of your updates later.

@RandyGaul
Copy link
Owner

RandyGaul commented Nov 23, 2024

cute itself always depend on SPIRV tools since it still needs to do reflection even without runtime compilation.

If we attach reflection info can we instead cut out SPIRV from CF runtime (other than SPIRV-Cross), unless online shader compilation is required? We can augment the bytecode blob struct with all necessary info. Thoughts? Just a few more structs to store extra reflection info for CF runtime, mainly uniform information.

The shader compiler has all it needs to output prebuilt shaders and setup a little reflection table of information. It could be a static array of structs holding uniform information and counts. CF_ShaderBytecode can store a pointer to the static table for prebuilt shaders. For runtime compilation, the reflection info could be initialized on the stack as-needed for online compilation.

@bullno1
Copy link
Contributor Author

bullno1 commented Nov 23, 2024

If we attach reflection info can we instead cut out SPIRV from CF runtime (other than SPIRV-Cross), unless online shader compilation is required? We can augment the bytecode blob struct with all necessary info. Thoughts? Just a few more structs to store extra reflection info for CF runtime, mainly uniform information.

Yes, that's the plan.
My previous comment was about the current state of the PR but I'm heading towards moving all Spirv dependencies (except for SPIRV-Cross) into cute-shader.


## Offline compilation

If you have a lot of shaders and want to avoid runtime compilation overhead, CF provides its own offline compiller: `cute-shaderc`.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compiller typo

#include <stddef.h>
#include <cute_shader_bytecode.h>

typedef struct cute_shader_define_t {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use CF_ style for structs, and brace on separate line

Copy link
Contributor Author

@bullno1 bullno1 Nov 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, for cute shader, it's not really part of CF's public API though. How should I name it:

  • CF_ShaderDefine: Might clash.
  • CF_CuteShaderDefine: A bit long but possible.
  • CSH_Define: CuteShader define.
  • CS_Define: But CS is already cute_sound

How should I name the functions:

  • cute_shader_init: The current.
  • cf_shader_init: May clash with the main CF.
  • cf_cute_shader_init: A bit long.
  • csh_init: Sounds like a shell (csh).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say just go with CF_ prefix

* @brief Information about an input of a vertex shader.
* @related CF_ShaderBytecode
*/
typedef struct CF_ShaderInputInfo {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate brace line

SHADER_TYPE_BUILTIN,
} shader_type_t;

static const char* parse_flag(const char* arg, const char* flag_name) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brace on different line

@RandyGaul
Copy link
Owner

Looking quite good, and nice job on the documentation. Let me know when you feel like it's ready for me to pull it down and try things out.

@bullno1
Copy link
Contributor Author

bullno1 commented Nov 24, 2024

Except for stylistic changes, which I'll get to later today, there should not be anymore implementation changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants