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

Add renderer feature support flags to shader preprocessor #6207

Open
lostminds opened this issue Jan 30, 2023 · 5 comments
Open

Add renderer feature support flags to shader preprocessor #6207

lostminds opened this issue Jan 30, 2023 · 5 comments

Comments

@lostminds
Copy link

Describe the project you are working on

Shaders for use in exports with different renderers (Forward+, Mobile or Compatibility for web)

Describe the problem or limitation you are having in your project

Different renderers support different sets of features. For example the new instance uniforms aren't supported in the Compatiblity renderer and textureLod is not supported on Mobile. If you use an unsupported feature in a shader, this will fail to compile and the material will not render.

Currently this means that either you need to settle for the lowest common supported features for your platforms, or make different shaders for different renderers and assign them using some mechanism on load based on the renderer to use the more advanced versions when supported.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

The recently added shader preprocessor could I think have the potential to make this process much smoother by adding symbols available to the preprocessor describing features available on the current renderer:

For example a RENDERER_FEATURE_INSTANCE_UNIFORMS that is defined when the renderer is Forward+ or Mobile and not on Compatibility renderer.

Using these symbols you could then write your shaders with fallbacks like:

#if defined(RENDERER_FEATURE_X)
<code that uses feature X>
#else
<fallback code>
#endif

Meaning this shader could compile and be used on any renderer, but only include feature X when it's supported.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

I'm not familiar with how the preprocessor is set up, but I imagine this could be done by the preprocessor asking the current renderer for a list of available supported features and then adding those as hidden #defines in some scope that is available to the shader preprocessor.

Another benefit to this approach is that as support for advanced features is added to renderers they can simply add these features to their list of supported features, and any shaders using these preprocessor symbols will compile using the now supported features automatically. Instead of the more clumsy approach of for example checking if we're using the mobile renderer and then applying the mobile version of the shader, which will not automatically update if the mobile renderer starts supporting more features.

Finally, since the visual shader system is as I understand it basically a shader code generator, this system could also use this preprocessor functionality to add fallbacks for features that are not supported on all renderers. For example making instance uniforms fall back to constants or shader uniforms if instance uniforms aren't supported instead of failing to compile.

If this enhancement will not be used often, can it be worked around with a few lines of script?

As discussed above you can work around this by making multiple shader versions for different renderers, but it has drawbacks as noted above.

Is there a reason why this should be core and not an add-on in the asset library?

I think both the shader preprocessor and renderer functionality that would be needed are part of the core.

@bitsawer
Copy link
Member

bitsawer commented Jan 31, 2023

Similar improvement proposal here: #5062, check out section 6. That and section 3 have PR's linked and waiting for review, but as they are new features they'll have to wait until 4.0 is ready and out of feature freeze. If suggestion 6 (godotengine/godot#71919) is merged, you could do something like this:

#if OS.get_current_rendering_method() == "forward_plus"

Which is a bit more typing than a default macro but allows for more complex logic. Also, OS.get_current_rendering_method() or similar needs to be exposed to GDScript, not sure if there is currently an easy way to get that info, other than maybe ProjectSettings. And if that is too much repeated typing, you could do things like this:

#define RENDERER_FORWARD_PLUS (OS.get_current_rendering_method() == "forward_plus)
#define RENDERER_VULKAN (OS.get_current_rendering_method() in ["forward_plus", "mobile"])
#define RENDERER_COMPATIBILITY  (OS.get_current_rendering_method() == "gl_compatibility")

#if RENDERER_FORWARD_PLUS 

@lostminds
Copy link
Author

Similar improvement proposal here: #5062, check out section 6

Ah, that's great to hear that something like that is already in the works! And as you write this could probably be enough to make these types of fallbacks.

However, as I tried to argue above I think it would be good to also expose support for the actual renderer features instead of just the renderer name or type, and have the renderer supply this list of supported features in some way. Basically to allow the renderers to add feature support in the future and then have shaders start using them, or even adding new renderers and still have old shaders know what features are supported.

@Calinou
Copy link
Member

Calinou commented Jan 31, 2023

However, as I tried to argue above I think it would be good to also expose support for the actual renderer features instead of just the renderer name or type, and have the renderer supply this list of supported features in some way. Basically to allow the renderers to add feature support in the future and then have shaders start using them, or even adding new renderers and still have old shaders know what features are supported.

This is similar to DisplayServer.has_feature() or JavaScript feature detection in principle, so I agree this makes sense.

@lostminds
Copy link
Author

As this issue shows godotengine/godot#72617 the renderer support symbols would probably need to be defined for each shader type as well in each renderer. As for example currently instance uniforms are supported in spatial shaders, but not in canvas_item shaders on Mobile and Forward+. So the preprocessor would need to take this into account somehow and use the correct set of feature support flags from the renderer based on the shader type.

@lostminds
Copy link
Author

I just found that there is a RenderingServer.has_feature() method, only the description in the docs says "Not yet implemented. Always returns false.". Maybe this could be a good candidate then for exposing this information to GDScript as well if something similar is already planned, and maybe reuse the same enums for the feature flags in shaders.

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

No branches or pull requests

3 participants