diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 365a3a3b847..4e8f782f250 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -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).
[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].
+
+ 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.
+
Max buffer size for blend shapes. Any blend shape bigger than this will not work.
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 4465feb9ba5..1c4fb5374b7 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1819,7 +1819,14 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform
GIProbeInstance *gipi = gi_probe_instance_owner.getptr(ridp[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);
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);
@@ -1831,7 +1838,11 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform
if (gi_probe_count > 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);
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);
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index c500a778d27..32c52bf8e2d 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -123,7 +123,7 @@ bool ShaderGLES3::_bind(bool p_binding_fallback) {
#ifdef DEBUG_ENABLED
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;
}
}
@@ -160,7 +160,7 @@ bool ShaderGLES3::_bind_ubershader() {
ERR_FAIL_COND_V(conditionals_uniform == -1, false);
#endif
new_conditional_version.version &= ~VersionKey::UBERSHADER_FLAG;
- glUniform1i(conditionals_uniform, new_conditional_version.version);
+ glUniform1ui(conditionals_uniform, new_conditional_version.version);
return bound;
}
@@ -454,11 +454,11 @@ static CharString _prepare_ubershader_chunk(const CharString &p_chunk) {
} else if (l.begins_with("#ifdef")) {
Vector pieces = l.split_spaces();
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")) {
Vector pieces = l.split_spaces();
CRASH_COND(pieces.size() != 2);
- s += "if ((ubershader_flags & FLAG_" + pieces[1] + ") == 0) {\n";
+ s += "if ((ubershader_flags & FLAG_" + pieces[1] + ") == 0u) {\n";
} else {
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) {
strings_common.push_back("#define IS_UBERSHADER\n");
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();
flag_macros.push_back(cs);
strings_common.push_back(cs.ptr());
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 58d6e41d6bf..74d47f2adba 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -399,6 +399,7 @@ public:
void free_custom_shader(uint32_t p_code_id);
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; }
virtual void init() = 0;
diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl
index 570e54e56dc..8863962ff0a 100644
--- a/drivers/gles3/shaders/particles.glsl
+++ b/drivers/gles3/shaders/particles.glsl
@@ -2,7 +2,7 @@
[vertex]
#if defined(IS_UBERSHADER)
-uniform highp int ubershader_flags;
+uniform highp uint ubershader_flags;
#endif
layout(location = 0) in highp vec4 color;
@@ -222,7 +222,7 @@ VERTEX_SHADER_CODE
[fragment]
#if defined(IS_UBERSHADER)
-uniform highp int ubershader_flags;
+uniform highp uint ubershader_flags;
#endif
// any code here is never executed, stuff is filled just so it works
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 375b58800cd..f1598bd901c 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -2,7 +2,7 @@
[vertex]
#if defined(IS_UBERSHADER)
-uniform highp int ubershader_flags;
+uniform highp uint ubershader_flags;
#endif
#define M_PI 3.14159265359
@@ -645,7 +645,7 @@ VERTEX_SHADER_CODE
[fragment]
#if defined(IS_UBERSHADER)
-uniform highp int ubershader_flags;
+uniform highp uint ubershader_flags;
// These are more performant and make the ubershaderification simpler
#define VCT_QUALITY_HIGH
#define USE_LIGHTMAP_FILTER_BICUBIC
@@ -1649,7 +1649,12 @@ uniform mediump vec4[12] lightmap_captures;
#ifdef USE_GI_PROBES //ubershader-skip
+#if !defined(IS_UBERSHADER)
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 vec3 gi_probe_bounds1;
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 bool gi_probe_blend_ambient1;
+#if !defined(IS_UBERSHADER)
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 vec3 gi_probe_bounds2;
uniform highp vec3 gi_probe_cell_size2;
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index b788bba180b..826ee9f8775 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -2727,6 +2727,7 @@ VisualServer::VisualServer() {
#endif
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"));
+ GLOBAL_DEF("rendering/gles3/shaders/shader_compilation_mode.mobile", 0);
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"));
GLOBAL_DEF("rendering/gles3/shaders/max_simultaneous_compiles.mobile", 1);