Fix T79146: Sculpt Mode lags until the entire mesh is visible

This was caused when the BKE_pbvh_draw_cb function was used with
update_only_visible set to false. In that case, all nodes with the flag
were updating, but the update flag was only cleared for visible nodes.
This was causing constant updates per redraw in no visible nodes until
they enter the view frustum and their flag was cleared.

In order to fix this and prevent it from happening again:
 - Updating the buffers, flushing the updates and clearing the flags are
now part of the same function. It does not make sense to do these in
separate places.

 - The BKE_pbvh_draw_cb function was refactored so the
pbvh_update_draw_buffers is only called once. It should now be easier to
understand what the function does when it is used to update only visible
nodes or all nodes.

Reviewed By: mont29

Maniphest Tasks: T79146

Differential Revision: https://developer.blender.org/D9935
This commit is contained in:
Pablo Dobarro 2021-01-05 20:23:25 +01:00
parent c20e482714
commit 2ed6055209
Notes: blender-bot 2023-02-14 02:27:56 +01:00
Referenced by issue #79146, Sculpt mode. Performance issues after enable/disable dyntopo with zoom
1 changed files with 30 additions and 33 deletions

View File

@ -1365,6 +1365,17 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode,
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings);
for (int i = 0; i < totnode; i++) {
PBVHNode *node = nodes[i];
if (node->flag & PBVH_UpdateDrawBuffers) {
/* Flush buffers uses OpenGL, so not in parallel. */
GPU_pbvh_buffers_update_flush(node->draw_buffers);
}
node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
}
}
static int pbvh_flush_bb(PBVH *pbvh, PBVHNode *node, int flag)
@ -2704,49 +2715,35 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
{
PBVHNode **nodes;
int totnode;
int update_flag = 0;
const int update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
if (!update_only_visible) {
/* Update all draw buffers, also those outside the view. */
/* Search for nodes that need updates. */
if (update_only_visible) {
/* Get visible nodes with draw updates. */
PBVHDrawSearchData data = {.frustum = update_frustum, .accum_update_flag = 0};
BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &data, &nodes, &totnode);
update_flag = data.accum_update_flag;
}
else {
/* Get all nodes with draw updates, also those outside the view. */
const int search_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
BKE_pbvh_search_gather(
pbvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode);
if (totnode) {
pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
}
MEM_SAFE_FREE(nodes);
pbvh, update_search_cb, POINTER_FROM_INT(search_flag), &nodes, &totnode);
update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
}
/* Gather visible nodes. */
PBVHDrawSearchData data = {.frustum = update_frustum, .accum_update_flag = 0};
BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &data, &nodes, &totnode);
if (update_only_visible && (data.accum_update_flag & update_flag)) {
/* Update draw buffers in visible nodes. */
pbvh_update_draw_buffers(pbvh, nodes, totnode, data.accum_update_flag);
/* Update draw buffers. */
if (totnode != 0 && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) {
pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
}
/* Draw. */
for (int a = 0; a < totnode; a++) {
PBVHNode *node = nodes[a];
if (node->flag & PBVH_UpdateDrawBuffers) {
/* Flush buffers uses OpenGL, so not in parallel. */
GPU_pbvh_buffers_update_flush(node->draw_buffers);
}
node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
}
MEM_SAFE_FREE(nodes);
/* Draw visible nodes. */
PBVHDrawSearchData draw_data = {.frustum = draw_frustum, .accum_update_flag = 0};
BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &draw_data, &nodes, &totnode);
for (int a = 0; a < totnode; a++) {
PBVHNode *node = nodes[a];
for (int i = 0; i < totnode; i++) {
PBVHNode *node = nodes[i];
if (!(node->flag & PBVH_FullyHidden)) {
draw_fn(user_data, node->draw_buffers);
}