diff options
Diffstat (limited to 'source/blender/blenlib/intern')
-rw-r--r-- | source/blender/blenlib/intern/cache_mutex.cc | 25 | ||||
-rw-r--r-- | source/blender/blenlib/intern/lazy_threading.cc | 30 | ||||
-rw-r--r-- | source/blender/blenlib/intern/math_rotation.c | 101 | ||||
-rw-r--r-- | source/blender/blenlib/intern/path_util.c | 22 | ||||
-rw-r--r-- | source/blender/blenlib/intern/string.c | 15 | ||||
-rw-r--r-- | source/blender/blenlib/intern/task_scheduler.cc | 2 | ||||
-rw-r--r-- | source/blender/blenlib/intern/uuid.cc | 27 | ||||
-rw-r--r-- | source/blender/blenlib/intern/winstuff.c | 14 |
8 files changed, 153 insertions, 83 deletions
diff --git a/source/blender/blenlib/intern/cache_mutex.cc b/source/blender/blenlib/intern/cache_mutex.cc new file mode 100644 index 00000000000..db474b1ef87 --- /dev/null +++ b/source/blender/blenlib/intern/cache_mutex.cc @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_cache_mutex.hh" +#include "BLI_task.hh" + +namespace blender { + +void CacheMutex::ensure(const FunctionRef<void()> compute_cache) +{ + if (cache_valid_.load(std::memory_order_acquire)) { + return; + } + std::scoped_lock lock{mutex_}; + /* Double checked lock. */ + if (cache_valid_.load(std::memory_order_relaxed)) { + return; + } + /* Use task isolation because a mutex is locked and the cache computation might use + * multi-threading. */ + threading::isolate_task(compute_cache); + + cache_valid_.store(true, std::memory_order_release); +} + +} // namespace blender diff --git a/source/blender/blenlib/intern/lazy_threading.cc b/source/blender/blenlib/intern/lazy_threading.cc index 803fd81a96d..4f6d3a75ecc 100644 --- a/source/blender/blenlib/intern/lazy_threading.cc +++ b/source/blender/blenlib/intern/lazy_threading.cc @@ -1,30 +1,50 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "BLI_lazy_threading.hh" +#include "BLI_stack.hh" #include "BLI_vector.hh" namespace blender::lazy_threading { /** - * This is a #RawVector so that it can be destructed after Blender checks for memory leaks. + * This uses a "raw" stack and vector so that it can be destructed after Blender checks for memory + * leaks. A new list of receivers is created whenever an isolated region is entered to avoid + * deadlocks. */ -thread_local RawVector<FunctionRef<void()>, 0> hint_receivers; +using HintReceivers = RawStack<RawVector<FunctionRef<void()>, 0>, 0>; +thread_local HintReceivers hint_receivers = []() { + HintReceivers receivers; + /* Make sure there is always at least one vector. */ + receivers.push_as(); + return receivers; +}(); void send_hint() { - for (const FunctionRef<void()> &fn : hint_receivers) { + for (const FunctionRef<void()> &fn : hint_receivers.peek()) { fn(); } } HintReceiver::HintReceiver(const FunctionRef<void()> fn) { - hint_receivers.append(fn); + hint_receivers.peek().append(fn); } HintReceiver::~HintReceiver() { - hint_receivers.pop_last(); + hint_receivers.peek().pop_last(); +} + +ReceiverIsolation::ReceiverIsolation() +{ + hint_receivers.push_as(); +} + +ReceiverIsolation::~ReceiverIsolation() +{ + BLI_assert(hint_receivers.peek().is_empty()); + hint_receivers.pop(); } } // namespace blender::lazy_threading diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index ff45bbee5c9..180412c4a14 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -275,64 +275,83 @@ void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3]) /* Caller must ensure matrices aren't negative for valid results, see: T24291, T94231. */ BLI_assert(!is_negative_m3(mat)); - /* Check the trace of the matrix - bad precision if close to -1. */ - const float trace = mat[0][0] + mat[1][1] + mat[2][2]; - - if (trace > 0) { - float s = 2.0f * sqrtf(1.0f + trace); - - q[0] = 0.25f * s; - - s = 1.0f / s; - - q[1] = (mat[1][2] - mat[2][1]) * s; - q[2] = (mat[2][0] - mat[0][2]) * s; - q[3] = (mat[0][1] - mat[1][0]) * s; - } - else { - /* Find the biggest diagonal element to choose the best formula. - * Here trace should also be always >= 0, avoiding bad precision. */ - if (mat[0][0] > mat[1][1] && mat[0][0] > mat[2][2]) { - float s = 2.0f * sqrtf(1.0f + mat[0][0] - mat[1][1] - mat[2][2]); - + /* Method outlined by Mike Day, ref: https://math.stackexchange.com/a/3183435/220949 + * with an additional `sqrtf(..)` for higher precision result. + * Removing the `sqrt` causes tests to fail unless the precision is set to 1e-6 or larger. */ + + if (mat[2][2] < 0.0f) { + if (mat[0][0] > mat[1][1]) { + const float trace = 1.0f + mat[0][0] - mat[1][1] - mat[2][2]; + float s = 2.0f * sqrtf(trace); + if (mat[1][2] < mat[2][1]) { + /* Ensure W is non-negative for a canonical result. */ + s = -s; + } q[1] = 0.25f * s; - s = 1.0f / s; - q[0] = (mat[1][2] - mat[2][1]) * s; - q[2] = (mat[1][0] + mat[0][1]) * s; + q[2] = (mat[0][1] + mat[1][0]) * s; q[3] = (mat[2][0] + mat[0][2]) * s; + if (UNLIKELY((trace == 1.0f) && (q[0] == 0.0f && q[2] == 0.0f && q[3] == 0.0f))) { + /* Avoids the need to normalize the degenerate case. */ + q[1] = 1.0f; + } } - else if (mat[1][1] > mat[2][2]) { - float s = 2.0f * sqrtf(1.0f + mat[1][1] - mat[0][0] - mat[2][2]); - + else { + const float trace = 1.0f - mat[0][0] + mat[1][1] - mat[2][2]; + float s = 2.0f * sqrtf(trace); + if (mat[2][0] < mat[0][2]) { + /* Ensure W is non-negative for a canonical result. */ + s = -s; + } q[2] = 0.25f * s; - s = 1.0f / s; - q[0] = (mat[2][0] - mat[0][2]) * s; - q[1] = (mat[1][0] + mat[0][1]) * s; - q[3] = (mat[2][1] + mat[1][2]) * s; + q[1] = (mat[0][1] + mat[1][0]) * s; + q[3] = (mat[1][2] + mat[2][1]) * s; + if (UNLIKELY((trace == 1.0f) && (q[0] == 0.0f && q[1] == 0.0f && q[3] == 0.0f))) { + /* Avoids the need to normalize the degenerate case. */ + q[2] = 1.0f; + } } - else { - float s = 2.0f * sqrtf(1.0f + mat[2][2] - mat[0][0] - mat[1][1]); - + } + else { + if (mat[0][0] < -mat[1][1]) { + const float trace = 1.0f - mat[0][0] - mat[1][1] + mat[2][2]; + float s = 2.0f * sqrtf(trace); + if (mat[0][1] < mat[1][0]) { + /* Ensure W is non-negative for a canonical result. */ + s = -s; + } q[3] = 0.25f * s; - s = 1.0f / s; - q[0] = (mat[0][1] - mat[1][0]) * s; q[1] = (mat[2][0] + mat[0][2]) * s; - q[2] = (mat[2][1] + mat[1][2]) * s; + q[2] = (mat[1][2] + mat[2][1]) * s; + if (UNLIKELY((trace == 1.0f) && (q[0] == 0.0f && q[1] == 0.0f && q[2] == 0.0f))) { + /* Avoids the need to normalize the degenerate case. */ + q[3] = 1.0f; + } } - - /* Make sure W is non-negative for a canonical result. */ - if (q[0] < 0) { - negate_v4(q); + else { + /* NOTE(@campbellbarton): A zero matrix will fall through to this block, + * needed so a zero scaled matrices to return a quaternion without rotation, see: T101848. */ + const float trace = 1.0f + mat[0][0] + mat[1][1] + mat[2][2]; + float s = 2.0f * sqrtf(trace); + q[0] = 0.25f * s; + s = 1.0f / s; + q[1] = (mat[1][2] - mat[2][1]) * s; + q[2] = (mat[2][0] - mat[0][2]) * s; + q[3] = (mat[0][1] - mat[1][0]) * s; + if (UNLIKELY((trace == 1.0f) && (q[1] == 0.0f && q[2] == 0.0f && q[3] == 0.0f))) { + /* Avoids the need to normalize the degenerate case. */ + q[0] = 1.0f; + } } } - normalize_qt(q); + BLI_assert(!(q[0] < 0.0f)); + BLI_ASSERT_UNIT_QUAT(q); } static void mat3_normalized_to_quat_with_checks(float q[4], float mat[3][3]) diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 179a1a305d1..2376bd82b69 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -123,7 +123,7 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort void BLI_path_sequence_encode( char *string, const char *head, const char *tail, ushort numlen, int pic) { - sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail); + BLI_sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail); } static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */ @@ -620,23 +620,12 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char } BLI_strncpy(extension, string + a, sizeof(extension)); - sprintf(string + a, "%s%s%s", sep, suffix, extension); + BLI_sprintf(string + a, "%s%s%s", sep, suffix, extension); return true; } bool BLI_path_parent_dir(char *path) { - char tmp[FILE_MAX]; - - STRNCPY(tmp, path); - /* Does all the work of normalizing the path for us. - * - * NOTE(@campbellbarton): While it's possible strip text after the second last slash, - * this would have to be clever and skip cases like "/./" & multiple slashes. - * Since this ends up solving some of the same problems as #BLI_path_normalize, - * call this function instead of attempting to handle them separately. */ - BLI_path_normalize(NULL, tmp); - /* Use #BLI_path_name_at_index instead of checking if the strings ends with `parent_dir` * to ensure the logic isn't confused by: * - Directory names that happen to end with `..`. @@ -644,18 +633,19 @@ bool BLI_path_parent_dir(char *path) * which would cause checking for a tailing `/../` fail. * Extracting the span of the final directory avoids both these issues. */ int tail_ofs = 0, tail_len = 0; - if (!BLI_path_name_at_index(tmp, -1, &tail_ofs, &tail_len)) { + if (!BLI_path_name_at_index(path, -1, &tail_ofs, &tail_len)) { return false; } if (tail_len == 1) { /* Last path is ".", as normalize should remove this, it's safe to assume failure. * This happens when the input a single period (possibly with slashes before or after). */ - if (tmp[tail_ofs] == '.') { + if (path[tail_ofs] == '.') { return false; } } - memcpy(path, tmp, tail_ofs); + /* Input paths should already be normalized if `..` is part of the path. */ + BLI_assert(!((tail_len == 2) && (path[tail_ofs] == '.') && (path[tail_ofs + 1] == '.'))); path[tail_ofs] = '\0'; return true; } diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 755d2dbd55d..3c3dcaf90f4 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -241,6 +241,17 @@ char *BLI_sprintfN(const char *__restrict format, ...) return n; } +int BLI_sprintf(char *__restrict str, const char *__restrict format, ...) +{ + va_list arg; + + va_start(arg, format); + const int result = vsprintf(str, format, arg); + va_end(arg); + + return result; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1114,7 +1125,7 @@ static size_t BLI_str_format_int_grouped_ex(char src[16], char dst[16], int num_ size_t BLI_str_format_int_grouped(char dst[16], int num) { char src[16]; - int num_len = sprintf(src, "%d", num); + const int num_len = BLI_snprintf(src, sizeof(src), "%d", num); return BLI_str_format_int_grouped_ex(src, dst, num_len); } @@ -1124,7 +1135,7 @@ size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) /* NOTE: Buffer to hold maximum `uint64`, which is 1.8e+19. but * we also need space for commas and null-terminator. */ char src[27]; - int num_len = sprintf(src, "%" PRIu64 "", num); + const int num_len = BLI_snprintf(src, sizeof(src), "%" PRIu64 "", num); return BLI_str_format_int_grouped_ex(src, dst, num_len); } diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc index 1f7747453c1..5b056df78b4 100644 --- a/source/blender/blenlib/intern/task_scheduler.cc +++ b/source/blender/blenlib/intern/task_scheduler.cc @@ -8,6 +8,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_lazy_threading.hh" #include "BLI_task.h" #include "BLI_threads.h" @@ -67,6 +68,7 @@ int BLI_task_scheduler_num_threads() void BLI_task_isolate(void (*func)(void *userdata), void *userdata) { #ifdef WITH_TBB + blender::lazy_threading::ReceiverIsolation isolation; tbb::this_task_arena::isolate([&] { func(userdata); }); #else func(userdata); diff --git a/source/blender/blenlib/intern/uuid.cc b/source/blender/blenlib/intern/uuid.cc index 023dd1ec409..b845208f0da 100644 --- a/source/blender/blenlib/intern/uuid.cc +++ b/source/blender/blenlib/intern/uuid.cc @@ -5,6 +5,7 @@ */ #include "BLI_assert.h" +#include "BLI_string.h" #include "BLI_uuid.h" #include <cstdio> @@ -85,19 +86,19 @@ bool BLI_uuid_equal(const bUUID uuid1, const bUUID uuid2) void BLI_uuid_format(char *buffer, const bUUID uuid) { - std::sprintf(buffer, - "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - uuid.time_low, - uuid.time_mid, - uuid.time_hi_and_version, - uuid.clock_seq_hi_and_reserved, - uuid.clock_seq_low, - uuid.node[0], - uuid.node[1], - uuid.node[2], - uuid.node[3], - uuid.node[4], - uuid.node[5]); + BLI_sprintf(buffer, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.time_low, + uuid.time_mid, + uuid.time_hi_and_version, + uuid.clock_seq_hi_and_reserved, + uuid.clock_seq_low, + uuid.node[0], + uuid.node[1], + uuid.node[2], + uuid.node[3], + uuid.node[4], + uuid.node[5]); } bool BLI_uuid_parse_string(bUUID *uuid, const char *buffer) diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c index 7e2c5e8f1dd..3a574b60ae2 100644 --- a/source/blender/blenlib/intern/winstuff.c +++ b/source/blender/blenlib/intern/winstuff.c @@ -110,7 +110,7 @@ bool BLI_windows_register_blend_extension(const bool background) &hkey, &dwd); if (lresult == ERROR_SUCCESS) { - sprintf(buffer, "\"%s\" \"%%1\"", BlPath); + BLI_snprintf(buffer, sizeof(buffer), "\"%s\" \"%%1\"", BlPath); lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, (BYTE *)buffer, strlen(buffer) + 1); RegCloseKey(hkey); } @@ -129,7 +129,7 @@ bool BLI_windows_register_blend_extension(const bool background) &hkey, &dwd); if (lresult == ERROR_SUCCESS) { - sprintf(buffer, "\"%s\", 1", BlPath); + BLI_snprintf(buffer, sizeof(buffer), "\"%s\", 1", BlPath); lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, (BYTE *)buffer, strlen(buffer) + 1); RegCloseKey(hkey); } @@ -167,10 +167,12 @@ bool BLI_windows_register_blend_extension(const bool background) RegCloseKey(root); printf("success (%s)\n", usr_mode ? "user" : "system"); if (!background) { - sprintf(MBox, - "File extension registered for %s.", - usr_mode ? "the current user. To register for all users, run as an administrator" : - "all users"); + BLI_snprintf(MBox, + sizeof(MBox), + "File extension registered for %s.", + usr_mode ? + "the current user. To register for all users, run as an administrator" : + "all users"); MessageBox(0, MBox, "Blender", MB_OK | MB_ICONINFORMATION); } return true; |