Improve ubershader compatibility

- Prevent debug enforced use of ubershader on shaders not supporting it
- Use unsigned integer for ubershader flags
- Add project setting for disabling async shader compilation on mobile
- Stop sampling some textures through different kinds of samplers at the same time
This commit is contained in:
Pedro J. Estébanez 2021-12-11 14:25:38 +01:00
parent 22166639ed
commit 0d1ec9a7cf
7 changed files with 38 additions and 11 deletions

View File

@ -1294,6 +1294,10 @@
To reduce loading times after the project has been launched at least once, you can use [code]Asynchronous + Cache[/code]. This also causes the ubershaders to be cached into storage so they can be ready faster next time they are used (provided the platform provides support for it). To reduce loading times after the project has been launched at least once, you can use [code]Asynchronous + Cache[/code]. This also causes the ubershaders to be cached into storage so they can be ready faster next time they are used (provided the platform provides support for it).
[b]Note:[/b] Asynchronous compilation is currently only supported for spatial (3D) and particle materials/shaders. CanvasItem (2D) shaders will not use asynchronous compilation even if this setting is set to [code]Asynchronous[/code] or [code]Asynchronous + Cache[/code]. [b]Note:[/b] Asynchronous compilation is currently only supported for spatial (3D) and particle materials/shaders. CanvasItem (2D) shaders will not use asynchronous compilation even if this setting is set to [code]Asynchronous[/code] or [code]Asynchronous + Cache[/code].
</member> </member>
<member name="rendering/gles3/shaders/shader_compilation_mode.mobile" type="int" setter="" getter="" default="0">
An override for [code]rendering/gles3/shaders/shader_compilation_mode[/code], so asynchronous compilation can be disabled for mobile.
You may want to do that since mobile GPUs generally won't support ubershaders due to their complexity.
</member>
<member name="rendering/limits/buffers/blend_shape_max_buffer_size_kb" type="int" setter="" getter="" default="4096"> <member name="rendering/limits/buffers/blend_shape_max_buffer_size_kb" type="int" setter="" getter="" default="4096">
Max buffer size for blend shapes. Any blend shape bigger than this will not work. Max buffer size for blend shapes. Any blend shape bigger than this will not work.
</member> </member>

View File

@ -1819,7 +1819,14 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform
GIProbeInstance *gipi = gi_probe_instance_owner.getptr(ridp[0]); GIProbeInstance *gipi = gi_probe_instance_owner.getptr(ridp[0]);
float bias_scale = e->instance->baked_light ? 1 : 0; float bias_scale = e->instance->baked_light ? 1 : 0;
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 10); // Normally, lightmapping uses the same texturing units than the GI probes; however, in the case of the ubershader
// that's not a good idea because some hardware/drivers (Android/Intel) may fail to render if a single texturing unit
// is used through multiple kinds of samplers in the same shader.
if (state.scene_shader.is_version_ubershader()) {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 12);
} else {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 10);
}
glBindTexture(GL_TEXTURE_3D, gipi->tex_cache); glBindTexture(GL_TEXTURE_3D, gipi->tex_cache);
state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM1, gipi->transform_to_data * p_view_transform); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM1, gipi->transform_to_data * p_view_transform);
state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS1, gipi->bounds); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS1, gipi->bounds);
@ -1831,7 +1838,11 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform
if (gi_probe_count > 1) { if (gi_probe_count > 1) {
GIProbeInstance *gipi2 = gi_probe_instance_owner.getptr(ridp[1]); GIProbeInstance *gipi2 = gi_probe_instance_owner.getptr(ridp[1]);
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 11); if (state.scene_shader.is_version_ubershader()) {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 13);
} else {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 11);
}
glBindTexture(GL_TEXTURE_3D, gipi2->tex_cache); glBindTexture(GL_TEXTURE_3D, gipi2->tex_cache);
state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM2, gipi2->transform_to_data * p_view_transform); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM2, gipi2->transform_to_data * p_view_transform);
state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS2, gipi2->bounds); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS2, gipi2->bounds);

View File

@ -123,7 +123,7 @@ bool ShaderGLES3::_bind(bool p_binding_fallback) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (ready) { if (ready) {
if (VS::get_singleton()->is_force_shader_fallbacks_enabled() && !must_be_ready_now) { if (VS::get_singleton()->is_force_shader_fallbacks_enabled() && !must_be_ready_now && get_ubershader_flags_uniform() != -1) {
ready = false; ready = false;
} }
} }
@ -160,7 +160,7 @@ bool ShaderGLES3::_bind_ubershader() {
ERR_FAIL_COND_V(conditionals_uniform == -1, false); ERR_FAIL_COND_V(conditionals_uniform == -1, false);
#endif #endif
new_conditional_version.version &= ~VersionKey::UBERSHADER_FLAG; new_conditional_version.version &= ~VersionKey::UBERSHADER_FLAG;
glUniform1i(conditionals_uniform, new_conditional_version.version); glUniform1ui(conditionals_uniform, new_conditional_version.version);
return bound; return bound;
} }
@ -454,11 +454,11 @@ static CharString _prepare_ubershader_chunk(const CharString &p_chunk) {
} else if (l.begins_with("#ifdef")) { } else if (l.begins_with("#ifdef")) {
Vector<String> pieces = l.split_spaces(); Vector<String> pieces = l.split_spaces();
CRASH_COND(pieces.size() != 2); CRASH_COND(pieces.size() != 2);
s += "if ((ubershader_flags & FLAG_" + pieces[1] + ") != 0) {\n"; s += "if ((ubershader_flags & FLAG_" + pieces[1] + ") != 0u) {\n";
} else if (l.begins_with("#ifndef")) { } else if (l.begins_with("#ifndef")) {
Vector<String> pieces = l.split_spaces(); Vector<String> pieces = l.split_spaces();
CRASH_COND(pieces.size() != 2); CRASH_COND(pieces.size() != 2);
s += "if ((ubershader_flags & FLAG_" + pieces[1] + ") == 0) {\n"; s += "if ((ubershader_flags & FLAG_" + pieces[1] + ") == 0u) {\n";
} else { } else {
CRASH_NOW_MSG("The shader template is using too complex syntax in a line marked with ubershader-runtime."); CRASH_NOW_MSG("The shader template is using too complex syntax in a line marked with ubershader-runtime.");
} }
@ -532,7 +532,7 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version(bool &r_async_forbidden)
if (build_ubershader) { if (build_ubershader) {
strings_common.push_back("#define IS_UBERSHADER\n"); strings_common.push_back("#define IS_UBERSHADER\n");
for (int i = 0; i < conditional_count; i++) { for (int i = 0; i < conditional_count; i++) {
String s = vformat("#define FLAG_%s (1 << %d)\n", String(conditional_defines[i]).strip_edges().trim_prefix("#define "), i); String s = vformat("#define FLAG_%s (1u << %du)\n", String(conditional_defines[i]).strip_edges().trim_prefix("#define "), i);
CharString cs = s.ascii(); CharString cs = s.ascii();
flag_macros.push_back(cs); flag_macros.push_back(cs);
strings_common.push_back(cs.ptr()); strings_common.push_back(cs.ptr());

View File

@ -399,6 +399,7 @@ public:
void free_custom_shader(uint32_t p_code_id); void free_custom_shader(uint32_t p_code_id);
uint32_t get_version() const { return new_conditional_version.version; } uint32_t get_version() const { return new_conditional_version.version; }
bool is_version_ubershader() const { return (new_conditional_version.version & VersionKey::UBERSHADER_FLAG); }
_FORCE_INLINE_ bool is_version_valid() const { return version && version->compile_status == Version::COMPILE_STATUS_OK; } _FORCE_INLINE_ bool is_version_valid() const { return version && version->compile_status == Version::COMPILE_STATUS_OK; }
virtual void init() = 0; virtual void init() = 0;

View File

@ -2,7 +2,7 @@
[vertex] [vertex]
#if defined(IS_UBERSHADER) #if defined(IS_UBERSHADER)
uniform highp int ubershader_flags; uniform highp uint ubershader_flags;
#endif #endif
layout(location = 0) in highp vec4 color; layout(location = 0) in highp vec4 color;
@ -222,7 +222,7 @@ VERTEX_SHADER_CODE
[fragment] [fragment]
#if defined(IS_UBERSHADER) #if defined(IS_UBERSHADER)
uniform highp int ubershader_flags; uniform highp uint ubershader_flags;
#endif #endif
// any code here is never executed, stuff is filled just so it works // any code here is never executed, stuff is filled just so it works

View File

@ -2,7 +2,7 @@
[vertex] [vertex]
#if defined(IS_UBERSHADER) #if defined(IS_UBERSHADER)
uniform highp int ubershader_flags; uniform highp uint ubershader_flags;
#endif #endif
#define M_PI 3.14159265359 #define M_PI 3.14159265359
@ -645,7 +645,7 @@ VERTEX_SHADER_CODE
[fragment] [fragment]
#if defined(IS_UBERSHADER) #if defined(IS_UBERSHADER)
uniform highp int ubershader_flags; uniform highp uint ubershader_flags;
// These are more performant and make the ubershaderification simpler // These are more performant and make the ubershaderification simpler
#define VCT_QUALITY_HIGH #define VCT_QUALITY_HIGH
#define USE_LIGHTMAP_FILTER_BICUBIC #define USE_LIGHTMAP_FILTER_BICUBIC
@ -1649,7 +1649,12 @@ uniform mediump vec4[12] lightmap_captures;
#ifdef USE_GI_PROBES //ubershader-skip #ifdef USE_GI_PROBES //ubershader-skip
#if !defined(IS_UBERSHADER)
uniform mediump sampler3D gi_probe1; //texunit:-10 uniform mediump sampler3D gi_probe1; //texunit:-10
#else
uniform mediump sampler3D gi_probe1_uber; //texunit:-12
#define gi_probe1 gi_probe1_uber
#endif
uniform highp mat4 gi_probe_xform1; uniform highp mat4 gi_probe_xform1;
uniform highp vec3 gi_probe_bounds1; uniform highp vec3 gi_probe_bounds1;
uniform highp vec3 gi_probe_cell_size1; uniform highp vec3 gi_probe_cell_size1;
@ -1658,7 +1663,12 @@ uniform highp float gi_probe_bias1;
uniform highp float gi_probe_normal_bias1; uniform highp float gi_probe_normal_bias1;
uniform bool gi_probe_blend_ambient1; uniform bool gi_probe_blend_ambient1;
#if !defined(IS_UBERSHADER)
uniform mediump sampler3D gi_probe2; //texunit:-11 uniform mediump sampler3D gi_probe2; //texunit:-11
#else
uniform mediump sampler3D gi_probe2_uber; //texunit:-13
#define gi_probe2 gi_probe2_uber
#endif
uniform highp mat4 gi_probe_xform2; uniform highp mat4 gi_probe_xform2;
uniform highp vec3 gi_probe_bounds2; uniform highp vec3 gi_probe_bounds2;
uniform highp vec3 gi_probe_cell_size2; uniform highp vec3 gi_probe_cell_size2;

View File

@ -2727,6 +2727,7 @@ VisualServer::VisualServer() {
#endif #endif
GLOBAL_DEF("rendering/gles3/shaders/shader_compilation_mode", 0); GLOBAL_DEF("rendering/gles3/shaders/shader_compilation_mode", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/gles3/shaders/shader_compilation_mode", PropertyInfo(Variant::INT, "rendering/gles3/shaders/shader_compilation_mode", PROPERTY_HINT_ENUM, "Synchronous,Asynchronous,Asynchronous + Cache")); ProjectSettings::get_singleton()->set_custom_property_info("rendering/gles3/shaders/shader_compilation_mode", PropertyInfo(Variant::INT, "rendering/gles3/shaders/shader_compilation_mode", PROPERTY_HINT_ENUM, "Synchronous,Asynchronous,Asynchronous + Cache"));
GLOBAL_DEF("rendering/gles3/shaders/shader_compilation_mode.mobile", 0);
GLOBAL_DEF("rendering/gles3/shaders/max_simultaneous_compiles", 2); GLOBAL_DEF("rendering/gles3/shaders/max_simultaneous_compiles", 2);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/gles3/shaders/max_simultaneous_compiles", PropertyInfo(Variant::INT, "rendering/gles3/shaders/max_simultaneous_compiles", PROPERTY_HINT_RANGE, "1,8,1")); ProjectSettings::get_singleton()->set_custom_property_info("rendering/gles3/shaders/max_simultaneous_compiles", PropertyInfo(Variant::INT, "rendering/gles3/shaders/max_simultaneous_compiles", PROPERTY_HINT_RANGE, "1,8,1"));
GLOBAL_DEF("rendering/gles3/shaders/max_simultaneous_compiles.mobile", 1); GLOBAL_DEF("rendering/gles3/shaders/max_simultaneous_compiles.mobile", 1);