cogl-bitmask: Use ffsl to speedup bitmask iteration
Instead of testing each bit when iterating a bitmask, we can use ffsl to skip over unset bits in single instruction. That way it will scale by the number of bits set, not the total number of bits. ffsl is a non-standard function which glibc only provides by defining GNUC_SOURCE. However if we are compiling with GCC we can avoid that mess and just use the equivalent builtin. When not compiling for GCC it will fall back to _cogl_util_ffs if the size of ints and longs are the same (which is the case on i686). Otherwise it fallbacks to a slow function implementation. Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
parent
f0f9493f5c
commit
2ba4fe417a
4 changed files with 51 additions and 9 deletions
|
@ -32,6 +32,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "cogl-bitmask.h"
|
#include "cogl-bitmask.h"
|
||||||
|
#include "cogl-util.h"
|
||||||
|
|
||||||
/* This code assumes that we can cast an unsigned long to a pointer
|
/* This code assumes that we can cast an unsigned long to a pointer
|
||||||
and back without losing any data */
|
and back without losing any data */
|
||||||
|
@ -245,12 +246,13 @@ _cogl_bitmask_foreach (const CoglBitmask *bitmask,
|
||||||
|
|
||||||
while (mask)
|
while (mask)
|
||||||
{
|
{
|
||||||
if (mask & 1UL)
|
int next_bit = _cogl_util_ffsl (mask);
|
||||||
func (array_index * sizeof (unsigned long) * 8 + bit,
|
|
||||||
user_data);
|
|
||||||
|
|
||||||
bit++;
|
bit += next_bit;
|
||||||
mask >>= 1;
|
mask >>= next_bit;
|
||||||
|
|
||||||
|
func (array_index * sizeof (unsigned long) * 8 + bit - 1,
|
||||||
|
user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,11 +263,12 @@ _cogl_bitmask_foreach (const CoglBitmask *bitmask,
|
||||||
|
|
||||||
while (mask)
|
while (mask)
|
||||||
{
|
{
|
||||||
if (mask & 1UL)
|
int next_bit = _cogl_util_ffsl (mask);
|
||||||
func (bit, user_data);
|
|
||||||
|
|
||||||
bit++;
|
bit += next_bit;
|
||||||
mask >>= 1;
|
mask >>= next_bit;
|
||||||
|
|
||||||
|
func (bit - 1, user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,3 +77,26 @@ _cogl_util_ffs (int num)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
#endif /* HAVE_FFS */
|
#endif /* HAVE_FFS */
|
||||||
|
|
||||||
|
/* The 'ffsl' is non-standard but when building with GCC we'll use its
|
||||||
|
builtin instead */
|
||||||
|
#ifndef COGL_UTIL_HAVE_BUILTIN_FFSL
|
||||||
|
|
||||||
|
int
|
||||||
|
_cogl_util_ffsl_wrapper (long int num)
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
if (num == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while ((num & 1) == 0)
|
||||||
|
{
|
||||||
|
num >>= 1;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* COGL_UTIL_HAVE_BUILTIN_FFSL */
|
||||||
|
|
|
@ -108,6 +108,21 @@ int
|
||||||
_cogl_util_ffs (int num);
|
_cogl_util_ffs (int num);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* The 'ffsl' function is non-standard but GCC has a builtin for it
|
||||||
|
since 3.4 which we can use */
|
||||||
|
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||||
|
#define _cogl_util_ffsl __builtin_ffsl
|
||||||
|
#define COGL_UTIL_HAVE_BUILTIN_FFSL
|
||||||
|
#else
|
||||||
|
/* If ints and longs are the same size we can just use ffs. Hopefully
|
||||||
|
the compiler will optimise away this conditional */
|
||||||
|
#define _cogl_util_ffsl(x) \
|
||||||
|
(sizeof (long int) == sizeof (int) ? _cogl_util_ffs ((int) x) : \
|
||||||
|
_cogl_util_ffsl_wrapper (x))
|
||||||
|
int
|
||||||
|
_cogl_util_ffsl_wrapper (long int num);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef COGL_HAS_GLIB_SUPPORT
|
#ifdef COGL_HAS_GLIB_SUPPORT
|
||||||
#define _COGL_RETURN_IF_FAIL(EXPR) g_return_if_fail(EXPR)
|
#define _COGL_RETURN_IF_FAIL(EXPR) g_return_if_fail(EXPR)
|
||||||
#define _COGL_RETURN_VAL_IF_FAIL(EXPR, VAL) g_return_val_if_fail(EXPR, VAL)
|
#define _COGL_RETURN_VAL_IF_FAIL(EXPR, VAL) g_return_val_if_fail(EXPR, VAL)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <cogl/cogl-bitmask.h>
|
#include <cogl/cogl-bitmask.h>
|
||||||
#include <cogl/cogl-bitmask.c>
|
#include <cogl/cogl-bitmask.c>
|
||||||
|
#include <cogl/cogl-util.c>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue