Merge branch 'master' into refactor-mesh-sharp-face-generic
This commit is contained in:
commit
2554861431
|
@ -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);
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ¶m_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
|
||||
|
|
|
@ -1094,6 +1094,8 @@ typedef struct ExplodeModifierData {
|
|||
} ExplodeModifierData;
|
||||
|
||||
typedef struct MultiresModifierData {
|
||||
DNA_DEFINE_CXX_METHODS(MultiresModifierData)
|
||||
|
||||
ModifierData modifier;
|
||||
|
||||
char lvl, sculptlvl, renderlvl, totlvl;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue