Merge branch 'master' into refactor-mesh-sharp-face-generic

This commit is contained in:
Hans Goudey 2023-01-22 10:24:08 -06:00
commit 2554861431
12 changed files with 184 additions and 81 deletions

View File

@ -464,12 +464,17 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, uint64_t tim
ndof_button_names[button]);
GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow();
const GHOST_TKey key = ghost_map_keyboard_from_ndof_buttom(button);
if (key != GHOST_kKeyUnknown) {
sendKeyEvent(key, press, time, window);
}
else {
sendButtonEvent(button, press, time, window);
/* Delivery will fail, so don't bother sending.
* Do, however update the buttons internal depressed state. */
if (window != nullptr) {
const GHOST_TKey key = ghost_map_keyboard_from_ndof_buttom(button);
if (key != GHOST_kKeyUnknown) {
sendKeyEvent(key, press, time, window);
}
else {
sendButtonEvent(button, press, time, window);
}
}
int mask = 1 << button_number;
@ -547,9 +552,11 @@ bool GHOST_NDOFManager::sendMotionEvent()
GHOST_IWindow *window = system_.getWindowManager()->getActiveWindow();
/* Delivery will fail, so don't bother sending. */
if (window == nullptr) {
motion_state_ = GHOST_kNotStarted; /* Avoid large `dt` times when changing windows. */
return false; /* Delivery will fail, so don't bother sending. */
/* Avoid large `dt` times when changing windows. */
motion_state_ = GHOST_kNotStarted;
return false;
}
GHOST_EventNDOFMotion *event = new GHOST_EventNDOFMotion(motion_time_, window);

View File

@ -276,7 +276,7 @@ struct TileChangeset {
const int chunk_len = chunk_x_len * chunk_y_len;
for (int chunk_index = 0; chunk_index < chunk_len; chunk_index++) {
chunk_dirty_flags_[chunk_index] = chunk_dirty_flags_[chunk_index] |
chunk_dirty_flags_[chunk_index] = chunk_dirty_flags_[chunk_index] ||
other.chunk_dirty_flags_[chunk_index];
}
has_dirty_chunks_ |= other.has_dirty_chunks_;

View File

@ -751,7 +751,7 @@ static DerivedMesh *multires_dm_create_local(Scene *scene,
bool alloc_paint_mask,
MultiresFlags flags)
{
MultiresModifierData mmd = {{nullptr}};
MultiresModifierData mmd{};
mmd.lvl = lvl;
mmd.sculptlvl = lvl;

View File

@ -84,7 +84,7 @@ bool multiresModifier_reshapeFromDeformModifier(Depsgraph *depsgraph,
MultiresModifierData *mmd,
ModifierData *deform_md)
{
MultiresModifierData highest_mmd = *mmd;
MultiresModifierData highest_mmd = blender::dna::shallow_copy(*mmd);
highest_mmd.sculptlvl = highest_mmd.totlvl;
highest_mmd.lvl = highest_mmd.totlvl;
highest_mmd.renderlvl = highest_mmd.totlvl;

View File

@ -71,6 +71,36 @@ void parallel_for(IndexRange range, int64_t grain_size, const Function &function
function(range);
}
/**
* Same as #parallel_for but tries to make the sub-range sizes multiples of the given alignment.
* This can improve performance when the range is processed using vectorized and/or unrolled loops,
* because the fallback loop that processes remaining values is used less often. A disadvantage of
* using this instead of #parallel_for is that the size differences between sub-ranges can be
* larger, which means that work is distributed less evenly.
*/
template<typename Function>
void parallel_for_aligned(const IndexRange range,
const int64_t grain_size,
const int64_t alignment,
const Function &function)
{
const int64_t global_begin = range.start();
const int64_t global_end = range.one_after_last();
const int64_t alignment_mask = ~(alignment - 1);
parallel_for(range, grain_size, [&](const IndexRange unaligned_range) {
/* Move the sub-range boundaries down to the next aligned index. The "global" begin and end
* remain fixed though. */
const int64_t unaligned_begin = unaligned_range.start();
const int64_t unaligned_end = unaligned_range.one_after_last();
const int64_t aligned_begin = std::max(global_begin, unaligned_begin & alignment_mask);
const int64_t aligned_end = unaligned_end == global_end ?
unaligned_end :
std::max(global_begin, unaligned_end & alignment_mask);
const IndexRange aligned_range{aligned_begin, aligned_end - aligned_begin};
function(aligned_range);
});
}
template<typename Value, typename Function, typename Reduction>
Value parallel_reduce(IndexRange range,
int64_t grain_size,

View File

@ -1506,7 +1506,7 @@ static void offset_meet(BevelParams *bp,
* Update: changed again from 0.0001f to fix bug T95335.
* Original two bugs remained fixed.
*/
#define BEVEL_GOOD_ANGLE 0.001f
#define BEVEL_GOOD_ANGLE 0.1f
/**
* Calculate the meeting point between e1 and e2 (one of which should have zero offsets),

View File

@ -221,7 +221,7 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l
DerivedMesh *dm;
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
Mesh *me = (Mesh *)ob->data;
MultiresModifierData tmp_mmd = *mmd;
MultiresModifierData tmp_mmd = blender::dna::shallow_copy(*mmd);
*lvl = mmd->lvl;
@ -246,7 +246,7 @@ static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *l
{
Mesh *me = (Mesh *)ob->data;
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
MultiresModifierData tmp_mmd = *mmd;
MultiresModifierData tmp_mmd = blender::dna::shallow_copy(*mmd);
DerivedMesh *cddm = CDDM_from_mesh(me);
DerivedMesh *dm;

View File

@ -1347,7 +1347,8 @@ static void uv_map_transform_center(const Scene *scene,
float r_bounds[2][3])
{
/* only operates on the edit object - this is all that's needed now */
const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS;
const int around = (v3d) ? scene->toolsettings->transform_pivot_point :
int(V3D_AROUND_CENTER_BOUNDS);
float bounds[2][3];
INIT_MINMAX(bounds[0], bounds[1]);
@ -2301,7 +2302,6 @@ static int smart_project_exec(bContext *C, wmOperator *op)
if (project_normal_array.size() == 0) {
MEM_freeN(thick_faces);
BLI_assert(project_normal_array == nullptr);
continue;
}

View File

@ -52,6 +52,64 @@ static int64_t compute_grain_size(const ExecutionHints &hints, const IndexMask m
return grain_size;
}
static int64_t compute_alignment(const int64_t grain_size)
{
if (grain_size <= 512) {
/* Don't use a number that's too large, or otherwise the work will be split quite unevenly. */
return 8;
}
/* It's not common that more elements are processed in a loop at once. */
return 32;
}
static void add_sliced_parameters(const Signature &signature,
Params &full_params,
const IndexRange slice_range,
ParamsBuilder &r_sliced_params)
{
for (const int param_index : signature.params.index_range()) {
const ParamType &param_type = signature.params[param_index].type;
switch (param_type.category()) {
case ParamCategory::SingleInput: {
const GVArray &varray = full_params.readonly_single_input(param_index);
r_sliced_params.add_readonly_single_input(varray.slice(slice_range));
break;
}
case ParamCategory::SingleMutable: {
const GMutableSpan span = full_params.single_mutable(param_index);
const GMutableSpan sliced_span = span.slice(slice_range);
r_sliced_params.add_single_mutable(sliced_span);
break;
}
case ParamCategory::SingleOutput: {
if (bool(signature.params[param_index].flag & ParamFlag::SupportsUnusedOutput)) {
const GMutableSpan span = full_params.uninitialized_single_output_if_required(
param_index);
if (span.is_empty()) {
r_sliced_params.add_ignored_single_output();
}
else {
const GMutableSpan sliced_span = span.slice(slice_range);
r_sliced_params.add_uninitialized_single_output(sliced_span);
}
}
else {
const GMutableSpan span = full_params.uninitialized_single_output(param_index);
const GMutableSpan sliced_span = span.slice(slice_range);
r_sliced_params.add_uninitialized_single_output(sliced_span);
}
break;
}
case ParamCategory::VectorInput:
case ParamCategory::VectorMutable:
case ParamCategory::VectorOutput: {
BLI_assert_unreachable();
break;
}
}
}
}
void MultiFunction::call_auto(IndexMask mask, Params params, Context context) const
{
if (mask.is_empty()) {
@ -71,71 +129,31 @@ void MultiFunction::call_auto(IndexMask mask, Params params, Context context) co
return;
}
threading::parallel_for(mask.index_range(), grain_size, [&](const IndexRange sub_range) {
const IndexMask sliced_mask = mask.slice(sub_range);
if (!hints.allocates_array) {
/* There is no benefit to changing indices in this case. */
this->call(sliced_mask, params, context);
return;
}
if (sliced_mask[0] < grain_size) {
/* The indices are low, no need to offset them. */
this->call(sliced_mask, params, context);
return;
}
const int64_t input_slice_start = sliced_mask[0];
const int64_t input_slice_size = sliced_mask.last() - input_slice_start + 1;
const IndexRange input_slice_range{input_slice_start, input_slice_size};
Vector<int64_t> offset_mask_indices;
const IndexMask offset_mask = mask.slice_and_offset(sub_range, offset_mask_indices);
ParamsBuilder offset_params{*this, offset_mask.min_array_size()};
/* Slice all parameters so that for the actual function call. */
for (const int param_index : this->param_indices()) {
const ParamType param_type = this->param_type(param_index);
switch (param_type.category()) {
case ParamCategory::SingleInput: {
const GVArray &varray = params.readonly_single_input(param_index);
offset_params.add_readonly_single_input(varray.slice(input_slice_range));
break;
const int64_t alignment = compute_alignment(grain_size);
threading::parallel_for_aligned(
mask.index_range(), grain_size, alignment, [&](const IndexRange sub_range) {
const IndexMask sliced_mask = mask.slice(sub_range);
if (!hints.allocates_array) {
/* There is no benefit to changing indices in this case. */
this->call(sliced_mask, params, context);
return;
}
case ParamCategory::SingleMutable: {
const GMutableSpan span = params.single_mutable(param_index);
const GMutableSpan sliced_span = span.slice(input_slice_range);
offset_params.add_single_mutable(sliced_span);
break;
if (sliced_mask[0] < grain_size) {
/* The indices are low, no need to offset them. */
this->call(sliced_mask, params, context);
return;
}
case ParamCategory::SingleOutput: {
if (bool(signature_ref_->params[param_index].flag & ParamFlag::SupportsUnusedOutput)) {
const GMutableSpan span = params.uninitialized_single_output_if_required(param_index);
if (span.is_empty()) {
offset_params.add_ignored_single_output();
}
else {
const GMutableSpan sliced_span = span.slice(input_slice_range);
offset_params.add_uninitialized_single_output(sliced_span);
}
}
else {
const GMutableSpan span = params.uninitialized_single_output(param_index);
const GMutableSpan sliced_span = span.slice(input_slice_range);
offset_params.add_uninitialized_single_output(sliced_span);
}
break;
}
case ParamCategory::VectorInput:
case ParamCategory::VectorMutable:
case ParamCategory::VectorOutput: {
BLI_assert_unreachable();
break;
}
}
}
const int64_t input_slice_start = sliced_mask[0];
const int64_t input_slice_size = sliced_mask.last() - input_slice_start + 1;
const IndexRange input_slice_range{input_slice_start, input_slice_size};
this->call(offset_mask, offset_params, context);
});
Vector<int64_t> offset_mask_indices;
const IndexMask offset_mask = mask.slice_and_offset(sub_range, offset_mask_indices);
ParamsBuilder sliced_params{*this, offset_mask.min_array_size()};
add_sliced_parameters(*signature_ref_, params, input_slice_range, sliced_params);
this->call(offset_mask, sliced_params, context);
});
}
std::string MultiFunction::debug_name() const

View File

@ -1094,6 +1094,8 @@ typedef struct ExplodeModifierData {
} ExplodeModifierData;
typedef struct MultiresModifierData {
DNA_DEFINE_CXX_METHODS(MultiresModifierData)
ModifierData modifier;
char lvl, sculptlvl, renderlvl, totlvl;

View File

@ -238,7 +238,6 @@ static void compute_point_counts_per_child(const bke::CurvesGeometry &guide_curv
{
const OffsetIndices guide_points_by_curve = guide_curves.points_by_curve();
threading::parallel_for(r_points_per_child.index_range(), 512, [&](const IndexRange range) {
int points_sum = 0;
for (const int child_curve_i : range) {
const int neighbor_count = all_neighbor_counts[child_curve_i];
if (neighbor_count == 0) {
@ -250,7 +249,6 @@ static void compute_point_counts_per_child(const bke::CurvesGeometry &guide_curv
const int points_per_curve_in_group = points_per_curve_by_group.lookup_default(group, -1);
if (points_per_curve_in_group != -1) {
r_points_per_child[child_curve_i] = points_per_curve_in_group;
points_sum += points_per_curve_in_group;
r_use_direct_interpolation[child_curve_i] = true;
continue;
}
@ -268,7 +266,6 @@ static void compute_point_counts_per_child(const bke::CurvesGeometry &guide_curv
const int points_in_child = std::max<int>(1, roundf(neighbor_points_weighted_sum));
r_points_per_child[child_curve_i] = points_in_child;
r_use_direct_interpolation[child_curve_i] = false;
points_sum += r_points_per_child[child_curve_i];
}
});
}

View File

@ -89,6 +89,20 @@
*/
#define USE_WIN_ACTIVATE
/**
* When the window is de-activated, release all held modifiers.
*
* Needed so events generated over unfocused (non-active) windows don't have modifiers held.
* Since modifier press/release events aren't send to unfocused windows it's best to assume
* modifiers are not pressed. This means when modifiers *are* held, events will incorrectly
* reported as not being held. Since this is standard behavior for Linux/MS-Window,
* opt to use this.
*
* NOTE(@campbellbarton): Events generated for non-active windows are rare,
* this happens when using the mouse-wheel over an unfocused window, see: T103722.
*/
#define USE_WIN_DEACTIVATE
/* the global to talk to ghost */
static GHOST_SystemHandle g_system = NULL;
#if !(defined(WIN32) || defined(__APPLE__))
@ -1130,6 +1144,41 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
switch (type) {
case GHOST_kEventWindowDeactivate:
#ifdef USE_WIN_DEACTIVATE
/* Release all held modifiers before de-activating the window. */
if (win->eventstate->modifier != 0) {
const uint8_t keymodifier_eventstate = win->eventstate->modifier;
const uint8_t keymodifier_l = wm_ghost_modifier_query(MOD_SIDE_LEFT);
const uint8_t keymodifier_r = wm_ghost_modifier_query(MOD_SIDE_RIGHT);
/* NOTE(@campbellbarton): when non-zero, there are modifiers held in
* `win->eventstate` which are not considered held by the GHOST internal state.
* While this should not happen, it's important all modifier held in event-state
* receive release events. Without this, so any events generated while the window
* is *not* active will have modifiers held. */
const uint8_t keymodifier_unhandled = keymodifier_eventstate &
~(keymodifier_l | keymodifier_r);
const uint8_t keymodifier_sided[2] = {
keymodifier_l | keymodifier_unhandled,
keymodifier_r,
};
GHOST_TEventKeyData kdata = {
.key = GHOST_kKeyUnknown,
.utf8_buf = {'\0'},
.is_repeat = false,
};
for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
if (keymodifier_eventstate & g_modifier_table[i].flag) {
for (int side = 0; side < 2; side++) {
if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
kdata.key = g_modifier_table[i].ghost_key_pair[side];
wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata);
}
}
}
}
}
#endif /* USE_WIN_DEACTIVATE */
wm_event_add_ghostevent(wm, win, type, data);
win->active = 0; /* XXX */
break;