diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 609cf35770d..69925990f60 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -60,6 +60,7 @@ RasterizerCanvasGLES2::BatchData::BatchData() { settings_colored_vertex_format_threshold = 0.0f; settings_batch_buffer_num_verts = 0; scissor_threshold_area = 0.0f; + prevent_color_baking = false; diagnose_frame = false; next_diagnose_tick = 10000; diagnose_frame_number = 9999999999; // some high number @@ -1687,7 +1688,9 @@ void RasterizerCanvasGLES2::flush_render_batches(Item *p_first_item, Item *p_cur bdata.use_colored_vertices = false; // only check whether to convert if there are quads (prevent divide by zero) - if (bdata.total_quads) { + // and we haven't decided to prevent color baking (due to e.g. MODULATE + // being used in a shader) + if (bdata.total_quads && !bdata.prevent_color_baking) { // minus 1 to prevent single primitives (ratio 1.0) always being converted to colored.. // in that case it is slightly cheaper to just have the color as part of the batch float ratio = (float)(bdata.total_color_changes - 1) / (float)bdata.total_quads; @@ -2252,6 +2255,16 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo bool unshaded = r_ris.shader_cache && (r_ris.shader_cache->canvas_item.light_mode == RasterizerStorageGLES2::Shader::CanvasItem::LIGHT_MODE_UNSHADED || (blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX && blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA)); bool reclip = false; + // does the shader contain BUILTINs which should break the batching? + if (r_ris.shader_cache && !unshaded) { + if (r_ris.shader_cache->canvas_item.prevent_color_baking) { + // we will do this same test on the shader during the rendering pass in order to set a bool not to bake vertex colors + // instead of saving this info as it is cheap to calculate + join = false; + r_batch_break = true; + } + } + // we are precalculating the final_modulate ahead of time because we need this for baking of final modulate into vertex colors // (only in software transform mode) // This maybe inefficient storing it... @@ -2974,6 +2987,14 @@ void RasterizerCanvasGLES2::render_joined_item(const BItemJoined &p_bij, RenderI bool unshaded = r_ris.shader_cache && (r_ris.shader_cache->canvas_item.light_mode == RasterizerStorageGLES2::Shader::CanvasItem::LIGHT_MODE_UNSHADED || (blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX && blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA)); bool reclip = false; + // does the shader contain BUILTINs which break the batching and should prevent color baking? + bdata.prevent_color_baking = false; + if (r_ris.shader_cache && !unshaded) { + if (r_ris.shader_cache->canvas_item.prevent_color_baking) { + bdata.prevent_color_baking = true; + } + } + if (r_ris.last_blend_mode != blend_mode) { switch (blend_mode) { diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index a82202157c8..3494b564f6c 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -200,6 +200,10 @@ class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 { // to alternate batching method and add color to the vertex format. int total_color_changes; + // if the shader is using MODULATE, we prevent baking so the final_modulate can + // be read in the shader + bool prevent_color_baking; + // measured in pixels, recalculated each frame float scissor_threshold_area; diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index a326338895d..e5a4926b33e 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -1424,6 +1424,9 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { p_shader->canvas_item.uses_screen_texture = false; p_shader->canvas_item.uses_screen_uv = false; p_shader->canvas_item.uses_time = false; + p_shader->canvas_item.uses_modulate = false; + p_shader->canvas_item.reads_color = false; + p_shader->canvas_item.prevent_color_baking = false; shaders.actions_canvas.render_mode_values["blend_add"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD); shaders.actions_canvas.render_mode_values["blend_mix"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX); @@ -1438,6 +1441,9 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { shaders.actions_canvas.usage_flag_pointers["SCREEN_PIXEL_SIZE"] = &p_shader->canvas_item.uses_screen_uv; shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture; shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time; + shaders.actions_canvas.usage_flag_pointers["MODULATE"] = &p_shader->canvas_item.uses_modulate; + + shaders.actions_canvas.read_flag_pointers["COLOR"] = &p_shader->canvas_item.reads_color; actions = &shaders.actions_canvas; actions->uniforms = &p_shader->uniforms; @@ -1525,6 +1531,11 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { p_shader->uses_vertex_time = gen_code.uses_vertex_time; p_shader->uses_fragment_time = gen_code.uses_fragment_time; + // some logic for batching + if (p_shader->mode == VS::SHADER_CANVAS_ITEM) { + p_shader->canvas_item.prevent_color_baking = p_shader->canvas_item.uses_modulate | p_shader->canvas_item.reads_color; + } + p_shader->shader->set_custom_shader(p_shader->custom_code_id); p_shader->shader->bind(); diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index c33f6952240..10ff8eb21d1 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -450,6 +450,13 @@ public: bool uses_screen_texture; bool uses_screen_uv; bool uses_time; + bool uses_modulate; + bool reads_color; + + // this flag is specifically for batching + // some of the logic is thus in rasterizer_storage.cpp + // we could alternatively set some bitflags here and test on the fly + bool prevent_color_baking; } canvas_item; diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index b253401db6c..c3b2e5e43dc 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -486,6 +486,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener *p_actions.write_flag_pointers[var_node->name] = true; } + if (!p_assigning && p_actions.read_flag_pointers.has(var_node->name)) { + *p_actions.read_flag_pointers[var_node->name] = true; + } + if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) { String define = p_default_actions.usage_defines[var_node->name]; String node_name = define.substr(1, define.length()); diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index 683c8bf3c45..d2ca19fa75c 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -44,6 +44,7 @@ public: Map > render_mode_values; Map render_mode_flags; Map usage_flag_pointers; + Map read_flag_pointers; Map write_flag_pointers; Map *uniforms;