Batching - store parent items in default batches

In rare cases default batches could occur which were containing commands that were not owned by the first item referenced by the joined item. This had assumed to be the case, and would read the wrong command, or crash.

Instead for safety in this PR we now store a pointer to the parent item in default batches, and use this to determine the correct command list instead of assuming.
This commit is contained in:
lawnjelly 2021-04-12 16:55:59 +01:00
parent 7a9c14e276
commit 40a267cf25
5 changed files with 31 additions and 14 deletions

View file

@ -295,7 +295,7 @@ void RasterizerCanvasGLES2::_batch_render_generic(const Batch &p_batch, Rasteriz
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void RasterizerCanvasGLES2::render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material) {
void RasterizerCanvasGLES2::render_batches(Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material) {
int num_batches = bdata.batches.size();
@ -318,9 +318,12 @@ void RasterizerCanvasGLES2::render_batches(Item::Command *const *p_commands, Ite
default: {
int end_command = batch.first_command + batch.num_commands;
RAST_DEV_DEBUG_ASSERT(batch.item);
RasterizerCanvas::Item::Command *const *commands = batch.item->commands.ptr();
for (int i = batch.first_command; i < end_command; i++) {
Item::Command *command = p_commands[i];
Item::Command *command = commands[i];
switch (command->type) {

View file

@ -55,7 +55,7 @@ private:
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);
bool try_join_item(Item *p_ci, RenderItemState &r_ris, bool &r_batch_break);
void render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
void render_batches(Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES2::Material *p_material);
// low level batch funcs
void _batch_upload_buffers();

View file

@ -502,7 +502,7 @@ void RasterizerCanvasGLES3::_legacy_canvas_render_item(Item *p_ci, RenderItemSta
}
}
void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES3::Material *p_material) {
void RasterizerCanvasGLES3::render_batches(Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES3::Material *p_material) {
// bdata.reset_flush();
// return;
@ -527,9 +527,12 @@ void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Ite
default: {
int end_command = batch.first_command + batch.num_commands;
RAST_DEV_DEBUG_ASSERT(batch.item);
RasterizerCanvas::Item::Command *const *commands = batch.item->commands.ptr();
for (int i = batch.first_command; i < end_command; i++) {
Item::Command *c = p_commands[i];
Item::Command *c = commands[i];
switch (c->type) {

View file

@ -58,7 +58,7 @@ private:
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);
bool try_join_item(Item *p_ci, RenderItemState &r_ris, bool &r_batch_break);
void render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES3::Material *p_material);
void render_batches(Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES3::Material *p_material);
// low level batch funcs
void _batch_upload_buffers();

View file

@ -184,7 +184,15 @@ public:
// first vertex of this batch in the vertex lists
uint32_t first_vert;
BatchColor color;
// we can keep the batch structure small because we either need to store
// the color if a handled batch, or the parent item if a default batch, so
// we can reference the correct originating command
union {
BatchColor color;
// for default batches we will store the parent item
const RasterizerCanvas::Item *item;
};
};
struct BatchTex {
@ -655,8 +663,11 @@ public:
RAST_DEBUG_ASSERT(batch);
}
if (p_blank)
if (p_blank) {
memset(batch, 0, sizeof(Batch));
} else {
batch->item = nullptr;
}
return batch;
}
@ -857,6 +868,7 @@ PREAMBLE(void)::_prefill_default_batch(FillState &r_fill_state, int p_command_nu
r_fill_state.curr_batch->type = RasterizerStorageCommon::BT_DEFAULT;
r_fill_state.curr_batch->first_command = extra_command;
r_fill_state.curr_batch->num_commands = 1;
r_fill_state.curr_batch->item = &p_item;
// revert to the original transform mode
// e.g. go back to NONE if we were in hardware transform mode
@ -882,6 +894,7 @@ PREAMBLE(void)::_prefill_default_batch(FillState &r_fill_state, int p_command_nu
r_fill_state.curr_batch->type = RasterizerStorageCommon::BT_DEFAULT;
r_fill_state.curr_batch->first_command = p_command_num;
r_fill_state.curr_batch->num_commands = 1;
r_fill_state.curr_batch->item = &p_item;
}
}
@ -2445,15 +2458,14 @@ PREAMBLE(void)::flush_render_batches(RasterizerCanvas::Item *p_first_item, Raste
// send buffers to opengl
get_this()->_batch_upload_buffers();
RasterizerCanvas::Item::Command *const *commands = p_first_item->commands.ptr();
#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED)
if (bdata.diagnose_frame) {
RasterizerCanvas::Item::Command *const *commands = p_first_item->commands.ptr();
diagnose_batches(commands);
}
#endif
get_this()->render_batches(commands, p_current_clip, r_reclip, p_material);
get_this()->render_batches(p_current_clip, r_reclip, p_material);
// if we overrode the fvf for lines, set it back to the joined item fvf
bdata.fvf = backup_fvf;
@ -2552,15 +2564,14 @@ PREAMBLE(void)::_legacy_canvas_item_render_commands(RasterizerCanvas::Item *p_it
int command_count = p_item->commands.size();
RasterizerCanvas::Item::Command *const *commands = p_item->commands.ptr();
// legacy .. just create one massive batch and render everything as before
bdata.batches.reset();
Batch *batch = _batch_request_new();
batch->type = RasterizerStorageCommon::BT_DEFAULT;
batch->num_commands = command_count;
batch->item = p_item;
get_this()->render_batches(commands, p_current_clip, r_reclip, p_material);
get_this()->render_batches(p_current_clip, r_reclip, p_material);
bdata.reset_flush();
}