From 1394df318855a4e143e5f668c2d38dfd3988d4fd Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Thu, 19 Nov 2020 15:09:33 +0000 Subject: [PATCH] Prevent item joining with custom shaders using selected BUILTINs Large FVF allows batching of many custom shaders, but should not join items which have shaders that utilize BUILTINs which would change for each item, because these will not be sent individually, and all joined items would wrongly use the values from the first joined item. --- drivers/gles2/rasterizer_canvas_gles2.cpp | 54 +++++++++++-------- drivers/gles2/rasterizer_storage_gles2.cpp | 13 +++++ drivers/gles2/rasterizer_storage_gles2.h | 6 +++ drivers/gles3/rasterizer_canvas_gles3.cpp | 52 ++++++++++-------- drivers/gles3/rasterizer_storage_gles3.cpp | 13 +++++ drivers/gles3/rasterizer_storage_gles3.h | 6 +++ .../gles_common/rasterizer_storage_common.h | 7 ++- 7 files changed, 106 insertions(+), 45 deletions(-) diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index f7b1546d5e..22ca8f8568 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -1372,33 +1372,42 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo bdata.joined_item_batch_flags = 0; if (r_ris.shader_cache) { - unsigned int and_flags = r_ris.shader_cache->canvas_item.batch_flags & (RasterizerStorageCommon::PREVENT_COLOR_BAKING | RasterizerStorageCommon::PREVENT_VERTEX_BAKING); + unsigned int and_flags = r_ris.shader_cache->canvas_item.batch_flags & (RasterizerStorageCommon::PREVENT_COLOR_BAKING | RasterizerStorageCommon::PREVENT_VERTEX_BAKING | RasterizerStorageCommon::PREVENT_ITEM_JOINING); if (and_flags) { - bool use_larger_fvfs = true; - - if (and_flags == RasterizerStorageCommon::PREVENT_COLOR_BAKING) { - // in some circumstances, if the modulate is identity, we still allow baking because reading modulate / color - // will still be okay to do in the shader with no ill effects - if (r_ris.final_modulate == Color(1, 1, 1, 1)) { - use_larger_fvfs = false; - } - } - - // new .. always use large FVF - if (use_larger_fvfs) { - if (and_flags == RasterizerStorageCommon::PREVENT_COLOR_BAKING) { - bdata.joined_item_batch_flags |= RasterizerStorageCommon::USE_MODULATE_FVF; - } else { - // we need to save on the joined item that it should use large fvf. - // This info will then be used in filling and rendering - bdata.joined_item_batch_flags |= RasterizerStorageCommon::USE_LARGE_FVF; - } + // special case for preventing item joining altogether + if (and_flags & RasterizerStorageCommon::PREVENT_ITEM_JOINING) { + join = false; + //r_batch_break = true; // don't think we need a batch break + // save the flags so that they don't need to be recalculated in the 2nd pass bdata.joined_item_batch_flags |= r_ris.shader_cache->canvas_item.batch_flags; - } + } else { - /* + bool use_larger_fvfs = true; + + if (and_flags == RasterizerStorageCommon::PREVENT_COLOR_BAKING) { + // in some circumstances, if the modulate is identity, we still allow baking because reading modulate / color + // will still be okay to do in the shader with no ill effects + if (r_ris.final_modulate == Color(1, 1, 1, 1)) { + use_larger_fvfs = false; + } + } + + // new .. always use large FVF + if (use_larger_fvfs) { + if (and_flags == RasterizerStorageCommon::PREVENT_COLOR_BAKING) { + bdata.joined_item_batch_flags |= RasterizerStorageCommon::USE_MODULATE_FVF; + } else { + // we need to save on the joined item that it should use large fvf. + // This info will then be used in filling and rendering + bdata.joined_item_batch_flags |= RasterizerStorageCommon::USE_LARGE_FVF; + } + + bdata.joined_item_batch_flags |= r_ris.shader_cache->canvas_item.batch_flags; + } + + /* if (and_flags == RasterizerStorageCommon::PREVENT_COLOR_BAKING) { // in some circumstances, if the modulate is identity, we still allow baking because reading modulate / color // will still be okay to do in the shader with no ill effects @@ -1424,6 +1433,7 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo bdata.joined_item_batch_flags |= r_ris.shader_cache->canvas_item.batch_flags; } */ + } // if not prevent item joining } } diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index d155d37217..322f63488c 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -1437,6 +1437,11 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { p_shader->canvas_item.uses_vertex = false; p_shader->canvas_item.batch_flags = 0; + p_shader->canvas_item.uses_world_matrix = false; + p_shader->canvas_item.uses_extra_matrix = false; + p_shader->canvas_item.uses_projection_matrix = false; + p_shader->canvas_item.uses_instance_custom = 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); shaders.actions_canvas.render_mode_values["blend_sub"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_SUB); @@ -1455,6 +1460,11 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { shaders.actions_canvas.usage_flag_pointers["VERTEX"] = &p_shader->canvas_item.uses_vertex; + shaders.actions_canvas.usage_flag_pointers["WORLD_MATRIX"] = &p_shader->canvas_item.uses_world_matrix; + shaders.actions_canvas.usage_flag_pointers["EXTRA_MATRIX"] = &p_shader->canvas_item.uses_extra_matrix; + shaders.actions_canvas.usage_flag_pointers["PROJECTION_MATRIX"] = &p_shader->canvas_item.uses_projection_matrix; + shaders.actions_canvas.usage_flag_pointers["INSTANCE_CUSTOM"] = &p_shader->canvas_item.uses_instance_custom; + actions = &shaders.actions_canvas; actions->uniforms = &p_shader->uniforms; } break; @@ -1558,6 +1568,9 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { if (p_shader->canvas_item.uses_vertex) { p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_VERTEX_BAKING; } + if (p_shader->canvas_item.uses_world_matrix | p_shader->canvas_item.uses_extra_matrix | p_shader->canvas_item.uses_projection_matrix | p_shader->canvas_item.uses_instance_custom) { + p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_ITEM_JOINING; + } } p_shader->shader->set_custom_shader(p_shader->custom_code_id); diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index f2024de128..28be646dbb 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -458,6 +458,12 @@ public: bool uses_color; bool uses_vertex; + // all these should disable item joining if used in a custom shader + bool uses_world_matrix; + bool uses_extra_matrix; + bool uses_projection_matrix; + bool uses_instance_custom; + } canvas_item; struct Spatial { diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 66ba398291..42480a8b2f 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1770,31 +1770,41 @@ bool RasterizerCanvasGLES3::try_join_item(Item *p_ci, RenderItemState &r_ris, bo bdata.joined_item_batch_flags = 0; if (r_ris.shader_cache) { - unsigned int and_flags = r_ris.shader_cache->canvas_item.batch_flags & (RasterizerStorageCommon::PREVENT_COLOR_BAKING | RasterizerStorageCommon::PREVENT_VERTEX_BAKING); + unsigned int and_flags = r_ris.shader_cache->canvas_item.batch_flags & (RasterizerStorageCommon::PREVENT_COLOR_BAKING | RasterizerStorageCommon::PREVENT_VERTEX_BAKING | RasterizerStorageCommon::PREVENT_ITEM_JOINING); if (and_flags) { - bool use_larger_fvfs = true; - - if (and_flags == RasterizerStorageCommon::PREVENT_COLOR_BAKING) { - // in some circumstances, if the modulate is identity, we still allow baking because reading modulate / color - // will still be okay to do in the shader with no ill effects - if (r_ris.final_modulate == Color(1, 1, 1, 1)) { - use_larger_fvfs = false; - } - } - - // new .. always use large FVF - if (use_larger_fvfs) { - if (and_flags == RasterizerStorageCommon::PREVENT_COLOR_BAKING) { - bdata.joined_item_batch_flags |= RasterizerStorageCommon::USE_MODULATE_FVF; - } else { - // we need to save on the joined item that it should use large fvf. - // This info will then be used in filling and rendering - bdata.joined_item_batch_flags |= RasterizerStorageCommon::USE_LARGE_FVF; - } + // special case for preventing item joining altogether + if (and_flags & RasterizerStorageCommon::PREVENT_ITEM_JOINING) { + join = false; + //r_batch_break = true; // don't think we need a batch break + // save the flags so that they don't need to be recalculated in the 2nd pass bdata.joined_item_batch_flags |= r_ris.shader_cache->canvas_item.batch_flags; - } + } else { + + bool use_larger_fvfs = true; + + if (and_flags == RasterizerStorageCommon::PREVENT_COLOR_BAKING) { + // in some circumstances, if the modulate is identity, we still allow baking because reading modulate / color + // will still be okay to do in the shader with no ill effects + if (r_ris.final_modulate == Color(1, 1, 1, 1)) { + use_larger_fvfs = false; + } + } + + // new .. always use large FVF + if (use_larger_fvfs) { + if (and_flags == RasterizerStorageCommon::PREVENT_COLOR_BAKING) { + bdata.joined_item_batch_flags |= RasterizerStorageCommon::USE_MODULATE_FVF; + } else { + // we need to save on the joined item that it should use large fvf. + // This info will then be used in filling and rendering + bdata.joined_item_batch_flags |= RasterizerStorageCommon::USE_LARGE_FVF; + } + + bdata.joined_item_batch_flags |= r_ris.shader_cache->canvas_item.batch_flags; + } + } // if not prevent item joining } } diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index bba60d1029..c22f12816c 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -2313,6 +2313,11 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { p_shader->canvas_item.uses_vertex = false; p_shader->canvas_item.batch_flags = 0; + p_shader->canvas_item.uses_world_matrix = false; + p_shader->canvas_item.uses_extra_matrix = false; + p_shader->canvas_item.uses_projection_matrix = false; + p_shader->canvas_item.uses_instance_custom = 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); shaders.actions_canvas.render_mode_values["blend_sub"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_SUB); @@ -2332,6 +2337,11 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { shaders.actions_canvas.usage_flag_pointers["COLOR"] = &p_shader->canvas_item.uses_color; shaders.actions_canvas.usage_flag_pointers["VERTEX"] = &p_shader->canvas_item.uses_vertex; + shaders.actions_canvas.usage_flag_pointers["WORLD_MATRIX"] = &p_shader->canvas_item.uses_world_matrix; + shaders.actions_canvas.usage_flag_pointers["EXTRA_MATRIX"] = &p_shader->canvas_item.uses_extra_matrix; + shaders.actions_canvas.usage_flag_pointers["PROJECTION_MATRIX"] = &p_shader->canvas_item.uses_projection_matrix; + shaders.actions_canvas.usage_flag_pointers["INSTANCE_CUSTOM"] = &p_shader->canvas_item.uses_instance_custom; + actions = &shaders.actions_canvas; actions->uniforms = &p_shader->uniforms; @@ -2436,6 +2446,9 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { if (p_shader->canvas_item.uses_vertex) { p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_VERTEX_BAKING; } + if (p_shader->canvas_item.uses_world_matrix | p_shader->canvas_item.uses_extra_matrix | p_shader->canvas_item.uses_projection_matrix | p_shader->canvas_item.uses_instance_custom) { + p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_ITEM_JOINING; + } } //all materials using this shader will have to be invalidated, unfortunately diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index a8800ba49b..f1fed7085e 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -473,6 +473,12 @@ public: bool uses_color; bool uses_vertex; + // all these should disable item joining if used in a custom shader + bool uses_world_matrix; + bool uses_extra_matrix; + bool uses_projection_matrix; + bool uses_instance_custom; + } canvas_item; struct Spatial { diff --git a/drivers/gles_common/rasterizer_storage_common.h b/drivers/gles_common/rasterizer_storage_common.h index e5750de9b9..aa81f2c260 100644 --- a/drivers/gles_common/rasterizer_storage_common.h +++ b/drivers/gles_common/rasterizer_storage_common.h @@ -48,8 +48,11 @@ public: PREVENT_COLOR_BAKING = 1 << 0, PREVENT_VERTEX_BAKING = 1 << 1, - USE_MODULATE_FVF = 1 << 2, - USE_LARGE_FVF = 1 << 3, + // custom vertex shaders using BUILTINS that vary per item + PREVENT_ITEM_JOINING = 1 << 2, + + USE_MODULATE_FVF = 1 << 3, + USE_LARGE_FVF = 1 << 4, }; enum BatchType : uint16_t {