sculpt-dev: Fix draw cache bug

Fix the pbvh draw optimization that only sends
active attributes to the GPU. The solution here
is the original sculpt-dev one (somehow this
ended up being removed but not replaced in the
pbvh-eevee patch).

It works by checking every viewport in every
window and if it finds eevee or workbench
in material mode it sets a flag in the pbvh
to forcibly upload all attributes.

Another approach is to simply rewrite pbvh
draw properly inside the draw manager to
begin with.
This commit is contained in:
Joseph Eagar 2022-06-14 09:52:34 -07:00
parent e108318af8
commit 47a14ef4ad
3 changed files with 57 additions and 39 deletions

View File

@ -870,7 +870,9 @@ void BKE_pbvh_free(PBVH *pbvh)
void BKE_pbvh_need_full_render_set(PBVH *pbvh, bool state)
{
GPU_pbvh_need_full_render_set(pbvh->vbo_id, state);
if (pbvh->vbo_id) {
GPU_pbvh_need_full_render_set(pbvh->vbo_id, state);
}
}
static void pbvh_iter_begin(PBVHIter *iter,
@ -1657,7 +1659,7 @@ void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node)
}
}
static void pbvh_check_draw_layout(PBVH *pbvh, bool full_render)
ATTR_NO_OPT static void pbvh_check_draw_layout(PBVH *pbvh, bool full_render)
{
const CustomData *vdata;
const CustomData *ldata;
@ -1687,6 +1689,8 @@ static void pbvh_check_draw_layout(PBVH *pbvh, bool full_render)
/* rebuild all draw buffers if attribute layout changed */
if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, !full_render)) {
printf("%s: draw update\n", __func__);
/* attribute layout changed; force rebuild */
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *node = pbvh->nodes + i;
@ -1701,29 +1705,10 @@ static void pbvh_check_draw_layout(PBVH *pbvh, bool full_render)
static void pbvh_update_draw_buffers(
PBVH *pbvh, Mesh *me, PBVHNode **nodes, int totnode, int update_flag)
{
const CustomData *vdata;
if (!pbvh->vbo_id) {
pbvh->vbo_id = GPU_pbvh_make_format();
}
switch (pbvh->type) {
case PBVH_BMESH:
if (!pbvh->bm) {
/* BMesh hasn't been created yet */
return;
}
vdata = &pbvh->bm->vdata;
break;
case PBVH_FACES:
vdata = pbvh->vdata;
break;
case PBVH_GRIDS:
vdata = NULL;
break;
}
if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
/* Free buffers uses OpenGL, so not in parallel. */
for (int n = 0; n < totnode; n++) {
@ -3265,6 +3250,10 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
int totnode;
int update_flag = 0;
if (pbvh->vbo_id) {
full_render |= GPU_pbvh_need_full_render_get(pbvh->vbo_id);
}
pbvh->draw_cache_invalid = false;
/* Search for nodes that need updates. */

View File

@ -36,6 +36,7 @@ struct ImBuf;
struct ImageFormatData;
struct Main;
struct MenuType;
struct PBVH;
struct PointerRNA;
struct PropertyRNA;
struct ScrArea;

View File

@ -27,10 +27,10 @@
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_pbvh.h"
#include "BKE_paint.h"
#include "GHOST_C-api.h"
@ -1194,16 +1194,24 @@ void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *UNUSED(region))
}
}
static void pbvh_full_render_update(PBVH *pbvh, bContext *C, Main *bmain, wmWindowManager *wm)
static void wm_pbvh_full_render_update(bContext *C)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
/*We can save GPU bandwidth for PBVH drawing if we know for sure that no
viewport has EEVEE running in it. As in no viewport in any windows.
/*
* We can save GPU bandwidth for PBVH drawing if we know for sure that no
* viewport has EEVEE running in it. As in no viewport in any windows.
*
* This saves us from having to upload every possible attribute eevee
* might need.
*
* This is because PBVH only supplies one set of drawing buffers
* to the draw manager. Creating more buffers for specific drawengines
* is simply not feasible for performance reasons.
*/
This is because PBVH only supplies one set of drawing buffers
to the draw manager. Creating more buffers for specific drawengines
is simply not feasible for performance reasons.
*/
bool need_full_render = false;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
@ -1214,7 +1222,12 @@ static void pbvh_full_render_update(PBVH *pbvh, bContext *C, Main *bmain, wmWind
CTX_wm_window_set(C, win);
BKE_pbvh_need_full_render_set(pbvh, false);
Object *ob = CTX_data_active_object(C);
if (!ob || !(ob->mode & OB_MODE_SCULPT) || !ob->sculpt || !ob->sculpt->pbvh) {
continue;
}
BKE_pbvh_need_full_render_set(ob->sculpt->pbvh, false);
if (wm_draw_update_test_window(bmain, C, win)) {
bScreen *screen = WM_window_get_active_screen(win);
@ -1226,13 +1239,31 @@ static void pbvh_full_render_update(PBVH *pbvh, bContext *C, Main *bmain, wmWind
}
CTX_wm_area_set(C, area);
View3D *v3d = CTX_wm_view3d(C);
if (v3d->shading.type >= OB_MATERIAL) {
BKE_pbvh_need_full_render_set(pbvh, true);
}
need_full_render |= v3d->shading.type >= OB_MATERIAL;
need_full_render |= v3d->shading.color_type == V3D_SHADING_MATERIAL_COLOR;
}
}
}
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
if (state == GHOST_kWindowStateMinimized) {
continue;
}
CTX_wm_window_set(C, win);
Object *ob = CTX_data_active_object(C);
if (!ob || !(ob->mode & OB_MODE_SCULPT) || !ob->sculpt || !ob->sculpt->pbvh) {
continue;
}
BKE_pbvh_need_full_render_set(ob->sculpt->pbvh, need_full_render);
}
}
void wm_draw_update(bContext *C)
@ -1247,11 +1278,6 @@ void wm_draw_update(bContext *C)
BKE_image_free_unused_gpu_textures();
Object *ob = CTX_data_active_object(C);
if (ob && (ob->mode & OB_MODE_SCULPT) && ob->sculpt && ob->sculpt->pbvh) {
pbvh_full_render_update(ob->sculpt->pbvh, C, bmain, wm);
}
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
#ifdef WIN32
GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
@ -1267,6 +1293,8 @@ void wm_draw_update(bContext *C)
CTX_wm_window_set(C, win);
wm_pbvh_full_render_update(C);
if (wm_draw_update_test_window(bmain, C, win)) {
bScreen *screen = WM_window_get_active_screen(win);