1
1

Compare commits

...

1 Commits

Author SHA1 Message Date
2e4e3adb3e Mesh performance tests 2021-05-04 18:02:25 +10:00
9 changed files with 240 additions and 2 deletions

View File

@@ -2279,6 +2279,20 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
)
class USERPREF_PT_experimental_mesh_perf(ExperimentalPanel, Panel):
bl_label = "Debugging"
def draw(self, context):
self._draw_items(
context, (
({"property": "use_mesh_no_tess_calc"}, None),
({"property": "use_mesh_no_normal_calc"}, None),
({"property": "use_mesh_no_transform_update"}, None),
({"property": "use_mesh_no_draw"}, None),
),
)
# -----------------------------------------------------------------------------
# Class Registration
@@ -2375,6 +2389,7 @@ classes = (
USERPREF_PT_experimental_new_features,
USERPREF_PT_experimental_prototypes,
USERPREF_PT_experimental_debugging,
USERPREF_PT_experimental_mesh_perf,
# Add dynamically generated editor theme panels last,
# so they show up last in the theme section.

View File

@@ -118,6 +118,10 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
((looptris_tot_prev_alloc >= looptris_tot) &&
(looptris_tot_prev_alloc <= looptris_tot * 2))) {
looptris = em->looptris;
if (U.experimental.use_mesh_no_tess_calc) {
return;
}
}
else {
if (em->looptris) {

View File

@@ -499,6 +499,10 @@ static void mesh_faces_calc_normals_cb(void *UNUSED(userdata), MempoolIterData *
*/
void BM_mesh_normals_update(BMesh *bm)
{
if (U.experimental.use_mesh_no_normal_calc) {
return;
}
float(*edgevec)[3] = MEM_mallocN(sizeof(*edgevec) * bm->totedge, __func__);
/* Parallel mempool iteration does not allow generating indices inline anymore... */
@@ -540,6 +544,10 @@ void BM_verts_calc_normal_vcos(BMesh *bm,
const float (*vcos)[3],
float (*vnos)[3])
{
if (U.experimental.use_mesh_no_normal_calc) {
return;
}
float(*edgevec)[3] = MEM_mallocN(sizeof(*edgevec) * bm->totedge, __func__);
/* Compute normalized direction vectors for each edge.
@@ -1355,6 +1363,10 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
const int cd_loop_clnors_offset,
const bool do_rebuild)
{
if (U.experimental.use_mesh_no_normal_calc) {
return;
}
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
if (use_split_normals) {

View File

@@ -1124,6 +1124,16 @@ bool deg_copy_on_write_is_expanded(const ID *id_cow)
bool deg_copy_on_write_is_needed(const ID *id_orig)
{
const ID_Type id_type = GS(id_orig->name);
if (U.experimental.use_mesh_no_transform_update) {
if (id_type == ID_ME) {
Mesh *me_orig = (Mesh *)id_orig;
if (me_orig->edit_mesh) {
return false;
}
}
}
return deg_copy_on_write_is_needed(id_type);
}

View File

@@ -1074,6 +1074,10 @@ static void drw_engines_cache_populate(Object *ob)
{
DST.ob_handle = 0;
if (U.experimental.use_mesh_no_draw) {
return;
}
/* HACK: DrawData is copied by COW from the duplicated object.
* This is valid for IDs that cannot be instantiated but this
* is not what we want in this case so we clear the pointer

View File

@@ -36,9 +36,14 @@
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_scene.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "WM_api.h"
#include "WM_types.h"
#include "DEG_depsgraph_query.h"
@@ -1676,7 +1681,9 @@ void recalcData_mesh(TransInfo *t)
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
DEG_id_tag_update(tc->obedit->data,
ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); /* sets recalc flags */
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
EDBM_mesh_normals_update(em);
BKE_editmesh_looptri_calc(em);

View File

@@ -646,7 +646,12 @@ typedef struct UserDef_Experimental {
char use_sculpt_tools_tilt;
char use_asset_browser;
char use_override_templates;
char _pad[6];
char use_mesh_no_tess_calc;
char use_mesh_no_transform_update;
char use_mesh_no_normal_calc;
char use_mesh_no_draw;
char _pad[2];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;

View File

@@ -6305,6 +6305,22 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1);
RNA_def_property_ui_text(
prop, "Override Templates", "Enable library override template in the python API");
prop = RNA_def_property(srna, "use_mesh_no_tess_calc", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_mesh_no_tess_calc", 1);
RNA_def_property_ui_text(prop, "No Mesh Tessellation Calculation", "XXX");
prop = RNA_def_property(srna, "use_mesh_no_transform_update", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_mesh_no_transform_update", 1);
RNA_def_property_ui_text(prop, "No Mesh COW Update in Edit Mode", "XXX");
prop = RNA_def_property(srna, "use_mesh_no_normal_calc", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_mesh_no_normal_calc", 1);
RNA_def_property_ui_text(prop, "No Mesh Normal Calculation", "XXX");
prop = RNA_def_property(srna, "use_mesh_no_draw", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_mesh_no_draw", 1);
RNA_def_property_ui_text(prop, "No Mesh Drawing", "XXX");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)

View File

@@ -0,0 +1,165 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
# Example usage:
#
# ./blender.bin --factory-startup --enable-event-simulate --python tests/python/transform_perf_benchmark.py
#
# Or to run on many files:
#
# find /d/perf_test -iname '*.blend' | sort | \
# xargs -I {} /src/cmake_release/bin/blender --factory-startup {} --enable-event-simulate --python tests/python/transform_perf_benchmark.py
import bpy
win = bpy.context.window_manager.windows[0]
# -----------------------------------------------------------------------------
# Simulate Events
def run_event_simulate(event_iter):
last_event = dict(
x = win.width // 2,
y = win.height // 2,
)
def event_step():
win = bpy.context.window_manager.windows[0]
val = next(event_step.run_events, Ellipsis)
if val is Ellipsis:
bpy.app.use_event_simulate = False
print("Finished simulation")
import sys; sys.exit(0)
return None
# Run event simulation.
for attr in ("x", "y"):
if attr in val:
last_event[attr] = val
else:
val[attr] = last_event[attr]
# Fake event value, since press, release is so common.
if val.get("value") == 'TAP':
del val["value"]
win.event_simulate(**val, value='PRESS')
win = bpy.context.window_manager.windows[0]
win.event_simulate(**val, value='RELEASE')
else:
win.event_simulate(**val)
return 0.0
event_step.run_events = iter(event_iter)
bpy.app.timers.register(event_step, first_interval=0.0, persistent=True)
def setup_default_preferences(preferences):
""" Set preferences useful for automation.
"""
preferences.view.show_splash = False
preferences.view.smooth_view = 0
preferences.view.use_save_prompt = False
preferences.view.show_developer_ui = True
preferences.filepaths.use_auto_save_temporary_files = False
def setup_experemental_preferences(preferences, attr, attr_default):
preferences.experimental.use_mesh_no_tess_calc = attr_default
preferences.experimental.use_mesh_no_normal_calc = attr_default
preferences.experimental.use_mesh_no_transform_update = attr_default
preferences.experimental.use_mesh_no_draw = attr_default
if attr:
setattr(preferences.experimental, attr, True)
def perform_coverage_test():
import os
import time
from math import sin, cos, pi
# Number of mouse steps.
steps = 128
# In pixels.
radius = 100
# Number of times to
times = 1
x_init = win.width // 2
y_init = win.height // 2
y_init_ofs = y_init + radius
yield dict(type='MOUSEMOVE', value='NOTHING', x=x_init, y=y_init)
# Maximize 3D view.
yield dict(type='SPACE', value='TAP', ctrl=True, alt=True, x=x_init, y=y_init)
print("\n" "Times for: %s" % os.path.basename(bpy.data.filepath))
for attr, attr_default in (
(None, False), # default (all on).
(None, True), # fast (all off).
("use_mesh_no_tess_calc", False),
("use_mesh_no_normal_calc", False),
("use_mesh_no_transform_update", False),
("use_mesh_no_draw", False),
):
setup_experemental_preferences(bpy.context.preferences, attr, attr_default)
# Start grab.
yield dict(type='G', value='TAP', x=x_init, y=y_init)
t = time.time()
step_total = 0
for _ in range(times):
for i in range(1, steps + 1):
phi = (i / steps) * 2.0 * pi
x_ofs = -radius * sin(phi)
y_ofs = +radius * cos(phi)
step_total += 1
yield dict(
type='MOUSEMOVE',
value='NOTHING',
x=int(x_init + x_ofs),
y=int((y_init + y_ofs) - radius),
)
delta = time.time() - t
delta_step = delta / step_total
print(
"%s: %s" % (
(attr or ("(default)" if attr_default is False else "(all_options_off)")).rjust(30),
("%.6f FPS" % (1 / delta_step)).rjust(10),
)
)
# Cancel transform.
yield dict(type='ESC', value='TAP', x=x_init, y=y_init)
print("\n")
def main():
setup_default_preferences(bpy.context.preferences)
run_event_simulate(perform_coverage_test())
if __name__ == "__main__":
main()