Fix #137869, #105665, #98339: Wrong or delayed mesh subdivision stats

* Fix CPU subdivided meshes not being counted
* Fix wrong check for GPU subdivision
* Draw status bar last so stats reflect latest 3D viewport drawing

Pull Request: https://projects.blender.org/blender/blender/pulls/137959
This commit is contained in:
Brecht Van Lommel
2025-04-24 15:59:58 +02:00
committed by Brecht Van Lommel
parent 84210efde8
commit 3ee7750fe1
2 changed files with 116 additions and 87 deletions

View File

@@ -102,22 +102,36 @@ static bool stats_mesheval(const Mesh *mesh_eval, bool is_selected, SceneStats *
int totvert, totedge, totface, totloop;
const SubsurfRuntimeData *subsurf_runtime_data = mesh_eval->runtime->subsurf_runtime_data;
/* Get multires stats. */
if (const std::unique_ptr<SubdivCCG> &subdiv_ccg = mesh_eval->runtime->subdiv_ccg) {
BKE_subdiv_ccg_topology_counters(*subdiv_ccg, totvert, totedge, totface, totloop);
}
else if (subsurf_runtime_data && subsurf_runtime_data->resolution != 0) {
totvert = subsurf_runtime_data->stats_totvert;
totedge = subsurf_runtime_data->stats_totedge;
totface = subsurf_runtime_data->stats_faces_num;
totloop = subsurf_runtime_data->stats_totloop;
}
else {
totvert = mesh_eval->verts_num;
totedge = mesh_eval->edges_num;
totface = mesh_eval->faces_num;
totloop = mesh_eval->corners_num;
/* Get CPU subdivided mesh if it exists. */
const SubsurfRuntimeData *subsurf_runtime_data = nullptr;
if (mesh_eval->runtime->mesh_eval) {
mesh_eval = mesh_eval->runtime->mesh_eval;
}
else {
subsurf_runtime_data = mesh_eval->runtime->subsurf_runtime_data;
}
/* Get GPU subdivision stats if they exist. If there is no 3D viewport or the mesh is
* hidden it will not be subdivided, fall back to unsubdivided in that case. */
if (subsurf_runtime_data && subsurf_runtime_data->has_gpu_subdiv &&
subsurf_runtime_data->stats_totvert)
{
totvert = subsurf_runtime_data->stats_totvert;
totedge = subsurf_runtime_data->stats_totedge;
totface = subsurf_runtime_data->stats_faces_num;
totloop = subsurf_runtime_data->stats_totloop;
}
else {
totvert = mesh_eval->verts_num;
totedge = mesh_eval->edges_num;
totface = mesh_eval->faces_num;
totloop = mesh_eval->corners_num;
}
}
stats->totvert += totvert;

View File

@@ -15,6 +15,7 @@
#include "DNA_listBase.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
@@ -928,100 +929,114 @@ GPUViewport *WM_draw_region_get_bound_viewport(ARegion *region)
return viewport;
}
static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
static void wm_draw_area_offscreen(bContext *C, wmWindow *win, ScrArea *area, bool stereo)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
bScreen *screen = WM_window_get_active_screen(win);
Main *bmain = CTX_data_main(C);
/* Draw screen areas into their own frame buffer. */
ED_screen_areas_iter (win, screen, area) {
CTX_wm_area_set(C, area);
GPU_debug_group_begin(wm_area_name(area));
CTX_wm_area_set(C, area);
GPU_debug_group_begin(wm_area_name(area));
/* Compute UI layouts for dynamically size regions. */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->flag & RGN_FLAG_POLL_FAILED) {
continue;
}
/* Dynamic region may have been flagged as too small because their size on init is 0.
* ARegion.visible is false then, as expected. The layout should still be created then, so
* the region size can be updated (it may turn out to be not too small then). */
const bool ignore_visibility = (region->flag & RGN_FLAG_DYNAMIC_SIZE) &&
(region->flag & RGN_FLAG_TOO_SMALL) &&
!(region->flag & RGN_FLAG_HIDDEN);
if ((region->runtime->visible || ignore_visibility) && region->runtime->do_draw &&
region->runtime->type && region->runtime->type->layout)
{
CTX_wm_region_set(C, region);
ED_region_do_layout(C, region);
CTX_wm_region_set(C, nullptr);
}
/* Compute UI layouts for dynamically size regions. */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->flag & RGN_FLAG_POLL_FAILED) {
continue;
}
/* Dynamic region may have been flagged as too small because their size on init is 0.
* ARegion.visible is false then, as expected. The layout should still be created then, so
* the region size can be updated (it may turn out to be not too small then). */
const bool ignore_visibility = (region->flag & RGN_FLAG_DYNAMIC_SIZE) &&
(region->flag & RGN_FLAG_TOO_SMALL) &&
!(region->flag & RGN_FLAG_HIDDEN);
ED_area_update_region_sizes(wm, win, area);
if (area->flag & AREA_FLAG_ACTIVE_TOOL_UPDATE) {
if ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
WM_toolsystem_update_from_context(
C, CTX_wm_workspace(C), CTX_data_scene(C), CTX_data_view_layer(C), area);
}
area->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE;
}
/* Then do actual drawing of regions. */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (!region->runtime->visible || !region->runtime->do_draw) {
continue;
}
if ((region->runtime->visible || ignore_visibility) && region->runtime->do_draw &&
region->runtime->type && region->runtime->type->layout)
{
CTX_wm_region_set(C, region);
bool use_viewport = WM_region_use_viewport(area, region);
ED_region_do_layout(C, region);
CTX_wm_region_set(C, nullptr);
}
}
GPU_debug_group_begin(use_viewport ? "Viewport" : "ARegion");
ED_area_update_region_sizes(wm, win, area);
if (stereo && wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID)) {
Scene *scene = WM_window_get_active_scene(win);
wm_draw_region_buffer_create(scene, region, true, use_viewport);
if (area->flag & AREA_FLAG_ACTIVE_TOOL_UPDATE) {
if ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
WM_toolsystem_update_from_context(
C, CTX_wm_workspace(C), CTX_data_scene(C), CTX_data_view_layer(C), area);
}
area->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE;
}
for (int view = 0; view < 2; view++) {
eStereoViews sview;
if (view == 0) {
sview = STEREO_LEFT_ID;
}
else {
sview = STEREO_RIGHT_ID;
wm_draw_region_stereo_set(bmain, area, region, sview);
}
/* Then do actual drawing of regions. */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (!region->runtime->visible || !region->runtime->do_draw) {
continue;
}
wm_draw_region_bind(region, view);
ED_region_do_draw(C, region);
wm_draw_region_unbind(region);
CTX_wm_region_set(C, region);
bool use_viewport = WM_region_use_viewport(area, region);
GPU_debug_group_begin(use_viewport ? "Viewport" : "ARegion");
if (stereo && wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID)) {
Scene *scene = WM_window_get_active_scene(win);
wm_draw_region_buffer_create(scene, region, true, use_viewport);
for (int view = 0; view < 2; view++) {
eStereoViews sview;
if (view == 0) {
sview = STEREO_LEFT_ID;
}
if (use_viewport) {
GPUViewport *viewport = region->runtime->draw_buffer->viewport;
GPU_viewport_stereo_composite(viewport, win->stereo3d_format);
else {
sview = STEREO_RIGHT_ID;
wm_draw_region_stereo_set(bmain, area, region, sview);
}
}
else {
wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID);
Scene *scene = WM_window_get_active_scene(win);
wm_draw_region_buffer_create(scene, region, false, use_viewport);
wm_draw_region_bind(region, 0);
wm_draw_region_bind(region, view);
ED_region_do_draw(C, region);
wm_draw_region_unbind(region);
}
GPU_debug_group_end();
region->runtime->do_draw = 0;
CTX_wm_region_set(C, nullptr);
if (use_viewport) {
GPUViewport *viewport = region->runtime->draw_buffer->viewport;
GPU_viewport_stereo_composite(viewport, win->stereo3d_format);
}
}
else {
wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID);
Scene *scene = WM_window_get_active_scene(win);
wm_draw_region_buffer_create(scene, region, false, use_viewport);
wm_draw_region_bind(region, 0);
ED_region_do_draw(C, region);
wm_draw_region_unbind(region);
}
CTX_wm_area_set(C, nullptr);
GPU_debug_group_end();
region->runtime->do_draw = 0;
CTX_wm_region_set(C, nullptr);
}
CTX_wm_area_set(C, nullptr);
GPU_debug_group_end();
}
static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
{
bScreen *screen = WM_window_get_active_screen(win);
/* Draw screen areas into their own frame buffer. Status bar is drawn last, because mesh
* and memory usage statistics are affected by drawing of editors. */
ED_screen_areas_iter (win, screen, area) {
if (area->spacetype != SPACE_STATUSBAR) {
wm_draw_area_offscreen(C, win, area, stereo);
}
}
ED_screen_areas_iter (win, screen, area) {
if (area->spacetype == SPACE_STATUSBAR) {
wm_draw_area_offscreen(C, win, area, stereo);
}
}
/* Draw menus into their own frame-buffer. */