utils: improve gst_util_ceil_log2

According to the following comparison of algorithms, the value
for 0 and 1 was giving an incorrect result.

https://gist.github.com/ceyusa/6061b33ac109a68bcd222f6919968c9a

More information here:
https://github.com/rofrol/codeforces/blob/master/ceil_log2.c

Use a different algorithm which offers better result and keep the
performance.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7429>
This commit is contained in:
Stéphane Cerveau 2024-08-30 13:21:30 +02:00 committed by GStreamer Marge Bot
parent 65e071c1c8
commit a6f82ba590
3 changed files with 41 additions and 20 deletions

View file

@ -57259,7 +57259,7 @@ element or %NULL if nothing was found</doc>
</parameters> </parameters>
</function> </function>
<function name="util_ceil_log2" c:identifier="gst_util_ceil_log2" version="1.24"> <function name="util_ceil_log2" c:identifier="gst_util_ceil_log2" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstutils.c">Return a max num of log2.</doc> <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstutils.c">Returns smallest integral value not less than log2(v).</doc>
<source-position filename="../subprojects/gstreamer/gst/gstutils.h"/> <source-position filename="../subprojects/gstreamer/gst/gstutils.h"/>
<return-value transfer-ownership="none"> <return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstutils.c">a computed #guint val.</doc> <doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstutils.c">a computed #guint val.</doc>

View file

@ -4484,7 +4484,7 @@ gst_bit_storage_uint64 (guint64 in)
* gst_util_ceil_log2: * gst_util_ceil_log2:
* @v: a #guint32 value. * @v: a #guint32 value.
* *
* Return a max num of log2. * Returns smallest integral value not less than log2(v).
* *
* Returns: a computed #guint val. * Returns: a computed #guint val.
* *
@ -4493,25 +4493,29 @@ gst_bit_storage_uint64 (guint64 in)
guint guint
gst_util_ceil_log2 (guint32 v) gst_util_ceil_log2 (guint32 v)
{ {
/* Compute Ceil(Log2(v)) */ static const unsigned int t[6] = {
/* Derived from branchless code for integer log2(v) from: 0x00000000ull,
<http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog> */ 0xFFFF0000ull,
guint r, shift; 0x0000FF00ull,
0x000000F0ull,
0x0000000Cull,
0x000000002ull
};
v--; g_return_val_if_fail (v != 0, -1);
r = (v > 0xFFFF) << 4;
v >>= r; int y = (((v & (v - 1)) == 0) ? 0 : 1);
shift = (v > 0xFF) << 3; int j = 32;
v >>= shift; int i;
r |= shift;
shift = (v > 0xF) << 2; for (i = 0; i < 6; i++) {
v >>= shift; int k = (((v & t[i]) == 0) ? 0 : j);
r |= shift; y += k;
shift = (v > 0x3) << 1; v >>= k;
v >>= shift; j >>= 1;
r |= shift; }
r |= (v >> 1);
return r + 1; return y;
} }
/** /**

View file

@ -1990,6 +1990,21 @@ GST_START_TEST (test_regression)
GST_END_TEST; GST_END_TEST;
// 10 Values
static const int ceil_log2_values[] = {
-1, 0, 1, 2, 2, 3, 3, 3, 3, 4
};
GST_START_TEST (test_ceil_log2)
{
int i;
for (i = 1; i < 10; i++) {
fail_unless_equals_int (gst_util_ceil_log2 (i), ceil_log2_values[i]);
}
}
GST_END_TEST;
GST_START_TEST (test_mark_as_plugin_api) GST_START_TEST (test_mark_as_plugin_api)
{ {
GstPluginAPIFlags api_flags; GstPluginAPIFlags api_flags;
@ -2053,6 +2068,8 @@ gst_utils_suite (void)
tcase_add_test (tc_chain, test_mark_as_plugin_api); tcase_add_test (tc_chain, test_mark_as_plugin_api);
tcase_add_test (tc_chain, test_ceil_log2);
return s; return s;
} }