diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 17d22b6b061..69d06251fff 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -67,16 +67,18 @@ RasterizerCanvasGLES2::BatchData::BatchData() { settings_scissor_threshold = -1.0f; } -RasterizerCanvasGLES2::RenderItemState::RenderItemState() { - current_clip = NULL; - shader_cache = NULL; +void RasterizerCanvasGLES2::RenderItemState::reset() { + current_clip = nullptr; + shader_cache = nullptr; rebind_shader = true; prev_use_skeleton = false; last_blend_mode = -1; canvas_last_material = RID(); item_group_z = 0; - item_group_light = 0; + item_group_light = nullptr; final_modulate = Color(-1.0, -1.0, -1.0, -1.0); // just something unlikely + + joined_item = nullptr; } RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_get_canvas_texture(const RID &p_texture) const { @@ -286,8 +288,8 @@ bool RasterizerCanvasGLES2::prefill_joined_item(FillState &r_fill_state, int &r_ _prefill_default_batch(r_fill_state, command_num); break; } - } - } // if use hardware transform + } // if use hardware transform + } Color col = rect->modulate; if (multiply_final_modulate) { @@ -1523,17 +1525,9 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *p_c render_batches(commands, p_current_clip, r_reclip, p_material); } -void RasterizerCanvasGLES2::join_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { - bdata.items_joined.reset(); - bdata.item_refs.reset(); +void RasterizerCanvasGLES2::join_items(Item *p_item_list, int p_z) { - RenderItemState render_item_state; - render_item_state.item_group_z = p_z; - render_item_state.item_group_modulate = p_modulate; - render_item_state.item_group_light = p_light; - render_item_state.item_group_base_transform = p_base_transform; - - BItemJoined *j = 0; + _render_item_state.item_group_z = p_z; // join is whether to join to the previous batch. // batch_break is whether to PREVENT the next batch from joining with us @@ -1554,17 +1548,17 @@ void RasterizerCanvasGLES2::join_items(Item *p_item_list, int p_z, const Color & // even though we know join is false. // also we need to run try_join_item for every item because it keeps the state up to date, // if we didn't run it the state would be out of date. - try_join_item(ci, render_item_state, batch_break); + try_join_item(ci, _render_item_state, batch_break); } else { - join = try_join_item(ci, render_item_state, batch_break); + join = try_join_item(ci, _render_item_state, batch_break); } // assume the first item will always return no join if (!join) { - j = bdata.items_joined.request_with_grow(); - j->first_item_ref = bdata.item_refs.size(); - j->num_item_refs = 1; - j->bounding_rect = ci->global_rect_cache; + _render_item_state.joined_item = bdata.items_joined.request_with_grow(); + _render_item_state.joined_item->first_item_ref = bdata.item_refs.size(); + _render_item_state.joined_item->num_item_refs = 1; + _render_item_state.joined_item->bounding_rect = ci->global_rect_cache; // add the reference BItemRef *r = bdata.item_refs.request_with_grow(); @@ -1573,23 +1567,22 @@ void RasterizerCanvasGLES2::join_items(Item *p_item_list, int p_z, const Color & // for baking into vertex colors. // this may not be ideal... as we are increasing the size of item reference, // but it is stupidly complex to calculate later, which would probably be slower. - r->final_modulate = render_item_state.final_modulate; + r->final_modulate = _render_item_state.final_modulate; } else { - CRASH_COND(j == 0); - j->num_item_refs += 1; - j->bounding_rect = j->bounding_rect.merge(ci->global_rect_cache); + CRASH_COND(_render_item_state.joined_item == 0); + _render_item_state.joined_item->num_item_refs += 1; + _render_item_state.joined_item->bounding_rect = _render_item_state.joined_item->bounding_rect.merge(ci->global_rect_cache); BItemRef *r = bdata.item_refs.request_with_grow(); r->item = ci; - r->final_modulate = render_item_state.final_modulate; + r->final_modulate = _render_item_state.final_modulate; } p_item_list = p_item_list->next; } } -void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { - +void RasterizerCanvasGLES2::canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { // if we are debugging, flash each frame between batching renderer and old version to compare for regressions if (bdata.settings_flash_batching) { if ((Engine::get_singleton()->get_frames_drawn() % 2) == 0) @@ -1598,15 +1591,44 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons bdata.settings_use_batching = false; } + if (!bdata.settings_use_batching) { + return; + } + // this only needs to be done when screen size changes, but this should be // infrequent enough _calculate_scissor_threshold_area(); - // state 1 : join similar items, so that their state changes are not repeated, - // and commands from joined items can be batched together - if (bdata.settings_use_batching) - join_items(p_item_list, p_z, p_modulate, p_light, p_base_transform); + // set up render item state for all the z_indexes (this is common to all z_indexes) + _render_item_state.reset(); + _render_item_state.item_group_modulate = p_modulate; + _render_item_state.item_group_light = p_light; + _render_item_state.item_group_base_transform = p_base_transform; +} +void RasterizerCanvasGLES2::canvas_render_items_end() { + if (!bdata.settings_use_batching) { + return; + } + + // batching render is deferred until after going through all the z_indices, joining all the items + canvas_render_items_implementation(0, 0, _render_item_state.item_group_modulate, + _render_item_state.item_group_light, + _render_item_state.item_group_base_transform); + + bdata.items_joined.reset(); + bdata.item_refs.reset(); +} + +void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { + // stage 1 : join similar items, so that their state changes are not repeated, + // and commands from joined items can be batched together + if (bdata.settings_use_batching) { + join_items(p_item_list, p_z); + return; + } + + // only legacy renders at this stage, batched renderer doesn't render until canvas_render_items_end() canvas_render_items_implementation(p_item_list, p_z, p_modulate, p_light, p_base_transform); } @@ -1767,6 +1789,9 @@ bool RasterizerCanvasGLES2::try_join_item(Item *p_ci, RenderItemState &r_ris, bo // a + light_blend + b + light_blend IS NOT THE SAME AS // a + b + light_blend join = false; + + // we also dont want to allow joining this item with the next item, because the next item could have no lights! + r_batch_break = true; } if (reclip) { diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index a1eab4fef41..cf8adba95e9 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -181,7 +181,8 @@ class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 { } bdata; struct RenderItemState { - RenderItemState(); + RenderItemState() { reset(); } + void reset(); Item *current_clip; RasterizerStorageGLES2::Shader *shader_cache; bool rebind_shader; @@ -190,12 +191,15 @@ class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 { RID canvas_last_material; Color final_modulate; + // used for joining items only + BItemJoined *joined_item; + // 'item group' is data over a single call to canvas_render_items int item_group_z; Color item_group_modulate; Light *item_group_light; Transform2D item_group_base_transform; - }; + } _render_item_state; struct FillState { void reset() { @@ -212,6 +216,8 @@ class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 { }; public: + virtual void canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); + virtual void canvas_render_items_end(); virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); private: @@ -222,7 +228,7 @@ private: // high level batch funcs void canvas_render_items_implementation(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); void render_joined_item(const BItemJoined &p_bij, RenderItemState &r_ris); - void join_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); + void join_items(Item *p_item_list, int p_z); bool try_join_item(Item *p_ci, RenderItemState &r_ris, bool &r_batch_break); void render_joined_item_commands(const BItemJoined &p_bij, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material); void render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 0f528ee161d..82d85ad7238 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -1066,6 +1066,8 @@ public: virtual void canvas_begin() = 0; virtual void canvas_end() = 0; + virtual void canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) {} + virtual void canvas_render_items_end() {} virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) = 0; virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0; diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index f7c53884fc7..f13d18e9090 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -42,11 +42,13 @@ void VisualServerCanvas::_render_canvas_item_tree(Item *p_canvas_item, const Tra _render_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL); + VSG::canvas_render->canvas_render_items_begin(p_modulate, p_lights, p_transform); for (int i = 0; i < z_range; i++) { if (!z_list[i]) continue; VSG::canvas_render->canvas_render_items(z_list[i], VS::CANVAS_ITEM_Z_MIN + i, p_modulate, p_lights, p_transform); } + VSG::canvas_render->canvas_render_items_end(); } void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2D p_transform, VisualServerCanvas::Item *p_material_owner, const Color p_modulate, VisualServerCanvas::Item **r_items, int &r_index) { @@ -259,6 +261,7 @@ void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_tr _render_canvas_item(ci[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, NULL, NULL); } + VSG::canvas_render->canvas_render_items_begin(p_canvas->modulate, p_lights, p_transform); for (int i = 0; i < z_range; i++) { if (!z_list[i]) continue; @@ -269,6 +272,7 @@ void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_tr VSG::canvas_render->canvas_render_items(z_list[i], VS::CANVAS_ITEM_Z_MIN + i, p_canvas->modulate, p_lights, p_transform); } + VSG::canvas_render->canvas_render_items_end(); } else { for (int i = 0; i < l; i++) {