Fix batching z_indices with z ranged lights

Joining items across z_indices can interfere with light culling for lights which only affect certain z ranges. This PR disables joining across z_indices when lights are present, except specifically for lights with both z_min set to the global minimum (-4096) and z_max set to the global maximum (4096).

In addition, the z_index is now stored on the joined_item for accurate light culling. The z_index is also displayed in frame diagnostics.
This commit is contained in:
lawnjelly 2020-04-23 11:50:49 +01:00
parent 3b44f34166
commit b954a8c099
2 changed files with 40 additions and 2 deletions

View file

@ -63,6 +63,7 @@ RasterizerCanvasGLES2::BatchData::BatchData() {
diagnose_frame = false; diagnose_frame = false;
next_diagnose_tick = 10000; next_diagnose_tick = 10000;
diagnose_frame_number = 9999999999; // some high number diagnose_frame_number = 9999999999; // some high number
join_across_z_indices = true;
settings_use_batching_original_choice = false; settings_use_batching_original_choice = false;
settings_flash_batching = false; settings_flash_batching = false;
@ -731,7 +732,7 @@ void RasterizerCanvasGLES2::diagnose_batches(Item::Command *const *p_commands) {
for (int batch_num = 0; batch_num < num_batches; batch_num++) { for (int batch_num = 0; batch_num < num_batches; batch_num++) {
const Batch &batch = bdata.batches[batch_num]; const Batch &batch = bdata.batches[batch_num];
bdata.frame_string += "\t\tbatch "; bdata.frame_string += "\t\t\tbatch ";
switch (batch.type) { switch (batch.type) {
case Batch::BT_RECT: { case Batch::BT_RECT: {
@ -1726,6 +1727,12 @@ void RasterizerCanvasGLES2::join_items(Item *p_item_list, int p_z) {
// batch_break must be preserved over z_indices, // batch_break must be preserved over z_indices,
// so is stored in _render_item_state.join_batch_break // so is stored in _render_item_state.join_batch_break
// if z ranged lights are present, sometimes we have to disable joining over z_indices.
// we do this here
if (!bdata.join_across_z_indices) {
_render_item_state.join_batch_break = true;
}
while (p_item_list) { while (p_item_list) {
Item *ci = p_item_list; Item *ci = p_item_list;
@ -1752,6 +1759,7 @@ void RasterizerCanvasGLES2::join_items(Item *p_item_list, int p_z) {
_render_item_state.joined_item->first_item_ref = bdata.item_refs.size(); _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->num_item_refs = 1;
_render_item_state.joined_item->bounding_rect = ci->global_rect_cache; _render_item_state.joined_item->bounding_rect = ci->global_rect_cache;
_render_item_state.joined_item->z_index = p_z;
// add the reference // add the reference
BItemRef *r = bdata.item_refs.request_with_grow(); BItemRef *r = bdata.item_refs.request_with_grow();
@ -1828,6 +1836,20 @@ void RasterizerCanvasGLES2::canvas_render_items_begin(const Color &p_modulate, L
// batch break must be preserved over the different z indices, // batch break must be preserved over the different z indices,
// to prevent joining to an item on a previous index if not allowed // to prevent joining to an item on a previous index if not allowed
_render_item_state.join_batch_break = false; _render_item_state.join_batch_break = false;
// whether to join across z indices depends on whether there are z ranged lights.
// joined z_index items can be wrongly classified with z ranged lights.
bdata.join_across_z_indices = true;
while (p_light) {
if ((p_light->z_min != VS::CANVAS_ITEM_Z_MIN) || (p_light->z_max != VS::CANVAS_ITEM_Z_MAX)) {
// prevent joining across z indices. This would have caused visual regressions
bdata.join_across_z_indices = false;
break;
}
p_light = p_light->next_ptr;
}
} }
void RasterizerCanvasGLES2::canvas_render_items_end() { void RasterizerCanvasGLES2::canvas_render_items_end() {
@ -2461,9 +2483,14 @@ void RasterizerCanvasGLES2::render_joined_item(const BItemJoined &p_bij, RenderI
storage->info.render._2d_item_count++; storage->info.render._2d_item_count++;
#ifdef DEBUG_ENABLED
if (bdata.diagnose_frame) { if (bdata.diagnose_frame) {
bdata.frame_string += "\tjoined_item " + itos(p_bij.num_item_refs) + " refs\n"; bdata.frame_string += "\tjoined_item " + itos(p_bij.num_item_refs) + " refs\n";
if (p_bij.z_index != 0) {
bdata.frame_string += "\t\t(z " + itos(p_bij.z_index) + ")\n";
}
} }
#endif
// all the joined items will share the same state with the first item // all the joined items will share the same state with the first item
Item *ci = bdata.item_refs[p_bij.first_item_ref].item; Item *ci = bdata.item_refs[p_bij.first_item_ref].item;
@ -2714,7 +2741,10 @@ void RasterizerCanvasGLES2::render_joined_item(const BItemJoined &p_bij, RenderI
// use the bounding rect of the joined items, NOT only the bounding rect of the first item. // use the bounding rect of the joined items, NOT only the bounding rect of the first item.
// note this is a cost of batching, the light culling will be less effective // note this is a cost of batching, the light culling will be less effective
if (ci->light_mask & light->item_mask && r_ris.item_group_z >= light->z_min && r_ris.item_group_z <= light->z_max && p_bij.bounding_rect.intersects_transformed(light->xform_cache, light->rect_cache)) {
// note that the r_ris.item_group_z will be out of date because we are using deferred rendering till canvas_render_items_end()
// so we have to test z against the stored value in the joined item
if (ci->light_mask & light->item_mask && p_bij.z_index >= light->z_min && p_bij.z_index <= light->z_max && p_bij.bounding_rect.intersects_transformed(light->xform_cache, light->rect_cache)) {
//intersects this light //intersects this light

View file

@ -122,6 +122,10 @@ class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 {
Rect2 bounding_rect; Rect2 bounding_rect;
// note the z_index may only be correct for the first of the joined item references
// this has implications for light culling with z ranged lights.
int z_index;
// we are always splitting items with lots of commands, // we are always splitting items with lots of commands,
// and items with unhandled primitives (default) // and items with unhandled primitives (default)
bool use_hardware_transform() const { return num_item_refs == 1; } bool use_hardware_transform() const { return num_item_refs == 1; }
@ -180,6 +184,10 @@ class RasterizerCanvasGLES2 : public RasterizerCanvasBaseGLES2 {
uint32_t next_diagnose_tick; uint32_t next_diagnose_tick;
uint64_t diagnose_frame_number; uint64_t diagnose_frame_number;
// whether to join items across z_indices - this can interfere with z ranged lights,
// so has to be disabled in some circumstances
bool join_across_z_indices;
// global settings // global settings
bool settings_use_batching; // the current use_batching (affected by flash) bool settings_use_batching; // the current use_batching (affected by flash)
bool settings_use_batching_original_choice; // the choice entered in project settings bool settings_use_batching_original_choice; // the choice entered in project settings