Batching - use FINAL_MODULATE_ALIAS in shaders

As part of the improvements to batch more cases, batching can store final_modulate as an attribute in the vertex format rather than sending as a uniform. This allows draw calls with different final_modulate to be batched together.

However custom shader code was reading from only the final_modulate uniform, and not the attribute when it was in use. This was leading to visual errors.

This is tricky to solve, because we cannot use the same name for the attribute in the vertex and fragment shaders, because one is an attribute and one a varying, whereas a uniform is accessible anywhere. To get around this, a macro is used which can translate to the most appropriate variable depending on whether uniform or attribute or varying is required.
This commit is contained in:
lawnjelly 2021-03-11 12:57:52 +00:00
parent 9952a5039a
commit 5ed0fd067d
4 changed files with 50 additions and 12 deletions

View File

@ -911,7 +911,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
actions[VS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom"; actions[VS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom";
actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color";
actions[VS::SHADER_CANVAS_ITEM].renames["MODULATE"] = "final_modulate"; actions[VS::SHADER_CANVAS_ITEM].renames["MODULATE"] = "final_modulate_alias";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth";

View File

@ -31,6 +31,17 @@ attribute vec2 uv_attrib; // attrib:4
attribute highp vec4 modulate_attrib; // attrib:5 attribute highp vec4 modulate_attrib; // attrib:5
#endif #endif
// Usually, final_modulate is passed as a uniform. However during batching
// If larger fvfs are used, final_modulate is passed as an attribute.
// we need to read from the attribute in custom vertex shader
// rather than the uniform. We do this by specifying final_modulate_alias
// in shaders rather than final_modulate directly.
#ifdef USE_ATTRIB_MODULATE
#define final_modulate_alias modulate_attrib
#else
#define final_modulate_alias final_modulate
#endif
#ifdef USE_ATTRIB_LARGE_VERTEX #ifdef USE_ATTRIB_LARGE_VERTEX
// shared with skeleton attributes, not used in batched shader // shared with skeleton attributes, not used in batched shader
attribute highp vec2 translate_attrib; // attrib:6 attribute highp vec2 translate_attrib; // attrib:6
@ -469,6 +480,18 @@ void main() {
normal_used = true; normal_used = true;
#endif #endif
// If larger fvfs are used, final_modulate is passed as an attribute.
// we need to read from this in custom fragment shaders or applying in the post step,
// rather than using final_modulate directly.
#if defined(final_modulate_alias)
#undef final_modulate_alias
#endif
#ifdef USE_ATTRIB_MODULATE
#define final_modulate_alias modulate_interp
#else
#define final_modulate_alias final_modulate
#endif
/* clang-format off */ /* clang-format off */
FRAGMENT_SHADER_CODE FRAGMENT_SHADER_CODE
@ -481,11 +504,7 @@ FRAGMENT_SHADER_CODE
} }
#if !defined(MODULATE_USED) #if !defined(MODULATE_USED)
#ifdef USE_ATTRIB_MODULATE color *= final_modulate_alias;
color *= modulate_interp;
#else
color *= final_modulate;
#endif
#endif #endif
#ifdef USE_LIGHTING #ifdef USE_LIGHTING

View File

@ -891,7 +891,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
actions[VS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom"; actions[VS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom";
actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color";
actions[VS::SHADER_CANVAS_ITEM].renames["MODULATE"] = "final_modulate"; actions[VS::SHADER_CANVAS_ITEM].renames["MODULATE"] = "final_modulate_alias";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth";

View File

@ -14,6 +14,17 @@ layout(location = 3) in vec4 color_attrib;
layout(location = 5) in vec4 modulate_attrib; // attrib:5 layout(location = 5) in vec4 modulate_attrib; // attrib:5
#endif #endif
// Usually, final_modulate is passed as a uniform. However during batching
// If larger fvfs are used, final_modulate is passed as an attribute.
// we need to read from the attribute in custom vertex shader
// rather than the uniform. We do this by specifying final_modulate_alias
// in shaders rather than final_modulate directly.
#ifdef USE_ATTRIB_MODULATE
#define final_modulate_alias modulate_attrib
#else
#define final_modulate_alias final_modulate
#endif
#ifdef USE_ATTRIB_LARGE_VERTEX #ifdef USE_ATTRIB_LARGE_VERTEX
// shared with skeleton attributes, not used in batched shader // shared with skeleton attributes, not used in batched shader
layout(location = 6) in vec2 translate_attrib; // attrib:6 layout(location = 6) in vec2 translate_attrib; // attrib:6
@ -567,6 +578,18 @@ void main() {
normal_used = true; normal_used = true;
#endif #endif
// If larger fvfs are used, final_modulate is passed as an attribute.
// we need to read from this in custom fragment shaders or applying in the post step,
// rather than using final_modulate directly.
#if defined(final_modulate_alias)
#undef final_modulate_alias
#endif
#ifdef USE_ATTRIB_MODULATE
#define final_modulate_alias modulate_interp
#else
#define final_modulate_alias final_modulate
#endif
/* clang-format off */ /* clang-format off */
FRAGMENT_SHADER_CODE FRAGMENT_SHADER_CODE
@ -582,12 +605,8 @@ FRAGMENT_SHADER_CODE
color = vec4(vec3(enc32), 1.0); color = vec4(vec3(enc32), 1.0);
#endif #endif
#ifdef USE_ATTRIB_MODULATE
color *= modulate_interp;
#else
#if !defined(MODULATE_USED) #if !defined(MODULATE_USED)
color *= final_modulate; color *= final_modulate_alias;
#endif
#endif #endif
#ifdef USE_LIGHTING #ifdef USE_LIGHTING