Browse Source

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
Pedro J. Estébanez 3 years ago
parent
commit
0d1ec9a7cf

+ 4 - 0
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).
 			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>

+ 13 - 2
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]);
 		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);

+ 5 - 5
drivers/gles3/shader_gles3.cpp

@@ -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());

+ 1 - 0
drivers/gles3/shader_gles3.h

@@ -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;

+ 2 - 2
drivers/gles3/shaders/particles.glsl

@@ -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

+ 12 - 2
drivers/gles3/shaders/scene.glsl

@@ -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;

+ 1 - 0
servers/visual_server.cpp

@@ -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);