diff options
author | Chun-wei Fan <fanchunwei@src.gnome.org> | 2011-11-18 12:23:25 +0800 |
---|---|---|
committer | Chun-wei Fan <fanchunwei@src.gnome.org> | 2011-11-18 12:23:25 +0800 |
commit | fc99756416f3231b3443871382ec972672d17375 (patch) | |
tree | 5e33a77badf1c426bd8203bee108ebf09790024e | |
parent | f5413e456456151b5d9cc9e80c8733675f8b7779 (diff) | |
parent | 3e56883c98584034f249b8eb938e65a129ccf8c4 (diff) | |
download | cogl-fc99756416f3231b3443871382ec972672d17375.tar.gz |
Merge branch 'master' into msvc-support
Conflicts:
cogl/cogl-debug.h
cogl/cogl-util.h
35 files changed, 2890 insertions, 519 deletions
diff --git a/cogl-pango/Makefile.am b/cogl-pango/Makefile.am index a4130309..d8cf3737 100644 --- a/cogl-pango/Makefile.am +++ b/cogl-pango/Makefile.am @@ -40,6 +40,7 @@ INCLUDES = \ -DCLUTTER_COMPILATION \ -DG_LOG_DOMAIN=\"CoglPango\" \ -I$(top_srcdir)/cogl \ + -I$(top_builddir)/cogl \ -I$(top_srcdir)/cogl/winsys \ -I$(top_srcdir) \ -I$(top_builddir) diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 9566571f..c870d814 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -327,6 +327,8 @@ cogl_sources_c = \ $(srcdir)/winsys/cogl-winsys-stub.c \ $(srcdir)/cogl-config-private.h \ $(srcdir)/cogl-config.c \ + $(srcdir)/cogl-boxed-value.h \ + $(srcdir)/cogl-boxed-value.c \ $(NULL) if SUPPORT_XLIB diff --git a/cogl/cogl-attribute.c b/cogl/cogl-attribute.c index 348071da..853d9893 100644 --- a/cogl/cogl-attribute.c +++ b/cogl/cogl-attribute.c @@ -428,13 +428,13 @@ validated: return status; } -static void +static gboolean toggle_enabled_cb (int bit_num, void *user_data) { const CoglBitmask *new_values = user_data; gboolean enabled = _cogl_bitmask_get (new_values, bit_num); - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _COGL_GET_CONTEXT (ctx, FALSE); if (ctx->driver == COGL_DRIVER_GLES2) { @@ -454,6 +454,8 @@ toggle_enabled_cb (int bit_num, void *user_data) GE( ctx, glDisableClientState (GL_TEXTURE_COORD_ARRAY) ); } #endif + + return TRUE; } static void diff --git a/cogl/cogl-bitmask.c b/cogl/cogl-bitmask.c index 568d549f..1d2f2f80 100644 --- a/cogl/cogl-bitmask.c +++ b/cogl/cogl-bitmask.c @@ -32,6 +32,19 @@ #include <string.h> #include "cogl-bitmask.h" +#include "cogl-util.h" +#include "cogl-flags.h" + +/* This code assumes that we can cast an unsigned long to a pointer + and back without losing any data */ +G_STATIC_ASSERT (sizeof (unsigned long) <= sizeof (void *)); + +#define ARRAY_INDEX(bit_num) \ + ((bit_num) / (sizeof (unsigned long) * 8)) +#define BIT_INDEX(bit_num) \ + ((bit_num) & (sizeof (unsigned long) * 8 - 1)) +#define BIT_MASK(bit_num) \ + (1UL << BIT_INDEX (bit_num)) gboolean _cogl_bitmask_get_from_array (const CoglBitmask *bitmask, @@ -41,22 +54,23 @@ _cogl_bitmask_get_from_array (const CoglBitmask *bitmask, /* If the index is off the end of the array then assume the bit is not set */ - if (bit_num >= sizeof (unsigned int) * 8 * array->len) + if (bit_num >= sizeof (unsigned long) * 8 * array->len) return FALSE; else - return !!(g_array_index (array, unsigned int, - bit_num / (sizeof (unsigned int) * 8)) & - (1 << (bit_num % (sizeof (unsigned int) * 8)))); + return !!(g_array_index (array, unsigned long, ARRAY_INDEX (bit_num)) & + BIT_MASK (bit_num)); } static void _cogl_bitmask_convert_to_array (CoglBitmask *bitmask) { GArray *array; - /* Fetch the old values, ignoring the least significant bit */ - unsigned int old_values = GPOINTER_TO_UINT (*bitmask) >> 1; + /* Fetch the old values */ + unsigned long old_values = _cogl_bitmask_to_bits (bitmask); - array = g_array_new (FALSE, TRUE, sizeof (unsigned int)); + array = g_array_new (FALSE, /* not zero-terminated */ + TRUE, /* do clear new entries */ + sizeof (unsigned long)); /* Copy the old values back in */ g_array_append_val (array, old_values); @@ -69,7 +83,8 @@ _cogl_bitmask_set_in_array (CoglBitmask *bitmask, gboolean value) { GArray *array; - unsigned int array_index, new_value_mask; + unsigned int array_index; + unsigned long new_value_mask; /* If the bitmask is not already an array then we need to allocate one */ if (!_cogl_bitmask_has_array (bitmask)) @@ -77,17 +92,17 @@ _cogl_bitmask_set_in_array (CoglBitmask *bitmask, array = (GArray *) *bitmask; - array_index = bit_num / (sizeof (unsigned int) * 8); + array_index = ARRAY_INDEX (bit_num); /* Grow the array if necessary. This will clear the new data */ if (array_index >= array->len) g_array_set_size (array, array_index + 1); - new_value_mask = 1 << (bit_num % (sizeof (unsigned int) * 8)); + new_value_mask = BIT_MASK (bit_num); if (value) - g_array_index (array, unsigned int, array_index) |= new_value_mask; + g_array_index (array, unsigned long, array_index) |= new_value_mask; else - g_array_index (array, unsigned int, array_index) &= ~new_value_mask; + g_array_index (array, unsigned long, array_index) &= ~new_value_mask; } void @@ -109,8 +124,8 @@ _cogl_bitmask_set_bits (CoglBitmask *dst, g_array_set_size (dst_array, src_array->len); for (i = 0; i < src_array->len; i++) - g_array_index (dst_array, unsigned int, i) |= - g_array_index (src_array, unsigned int, i); + g_array_index (dst_array, unsigned long, i) |= + g_array_index (src_array, unsigned long, i); } else if (_cogl_bitmask_has_array (dst)) { @@ -118,12 +133,12 @@ _cogl_bitmask_set_bits (CoglBitmask *dst, dst_array = (GArray *) *dst; - g_array_index (dst_array, unsigned int, 0) |= - (GPOINTER_TO_UINT (*src) >> 1); + g_array_index (dst_array, unsigned long, 0) |= + _cogl_bitmask_to_bits (src); } else - *dst = GUINT_TO_POINTER (GPOINTER_TO_UINT (*dst) | - GPOINTER_TO_UINT (*src)); + *dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) | + _cogl_bitmask_to_bits (src)); } void @@ -144,9 +159,9 @@ _cogl_bitmask_set_range_in_array (CoglBitmask *bitmask, array = (GArray *) *bitmask; /* Get the array index of the top most value that will be touched */ - array_index = (n_bits - 1) / (sizeof (unsigned int) * 8); + array_index = ARRAY_INDEX (n_bits - 1); /* Get the bit index of the top most value */ - bit_index = (n_bits - 1) % (sizeof (unsigned int) * 8); + bit_index = BIT_INDEX (n_bits - 1); /* Grow the array if necessary. This will clear the new data */ if (array_index >= array->len) g_array_set_size (array, array_index + 1); @@ -154,20 +169,19 @@ _cogl_bitmask_set_range_in_array (CoglBitmask *bitmask, if (value) { /* Set the bits that are touching this index */ - g_array_index (array, unsigned int, array_index) |= - ~(unsigned int) 0 >> (sizeof (unsigned int) * 8 - 1 - bit_index); + g_array_index (array, unsigned long, array_index) |= + ~0UL >> (sizeof (unsigned long) * 8 - 1 - bit_index); /* Set all of the bits in any lesser indices */ - memset (array->data, 0xff, sizeof (unsigned int) * array_index); + memset (array->data, 0xff, sizeof (unsigned long) * array_index); } else { /* Clear the bits that are touching this index */ - g_array_index (array, unsigned int, array_index) &= - ~(unsigned int) 1 << bit_index; + g_array_index (array, unsigned long, array_index) &= ~1UL << bit_index; /* Clear all of the bits in any lesser indices */ - memset (array->data, 0x00, sizeof (unsigned int) * array_index); + memset (array->data, 0x00, sizeof (unsigned long) * array_index); } } @@ -190,8 +204,8 @@ _cogl_bitmask_xor_bits (CoglBitmask *dst, g_array_set_size (dst_array, src_array->len); for (i = 0; i < src_array->len; i++) - g_array_index (dst_array, unsigned int, i) ^= - g_array_index (src_array, unsigned int, i); + g_array_index (dst_array, unsigned long, i) ^= + g_array_index (src_array, unsigned long, i); } else if (_cogl_bitmask_has_array (dst)) { @@ -199,12 +213,12 @@ _cogl_bitmask_xor_bits (CoglBitmask *dst, dst_array = (GArray *) *dst; - g_array_index (dst_array, unsigned int, 0) ^= - (GPOINTER_TO_UINT (*src) >> 1); + g_array_index (dst_array, unsigned long, 0) ^= + _cogl_bitmask_to_bits (src); } else - *dst = GUINT_TO_POINTER ((GPOINTER_TO_UINT (*dst) ^ - GPOINTER_TO_UINT (*src)) | 1); + *dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) ^ + _cogl_bitmask_to_bits (src)); } void @@ -212,46 +226,86 @@ _cogl_bitmask_clear_all_in_array (CoglBitmask *bitmask) { GArray *array = (GArray *) *bitmask; - memset (array->data, 0, sizeof (unsigned int) * array->len); + memset (array->data, 0, sizeof (unsigned long) * array->len); } void _cogl_bitmask_foreach (const CoglBitmask *bitmask, CoglBitmaskForeachFunc func, - gpointer user_data) + void *user_data) { if (_cogl_bitmask_has_array (bitmask)) { GArray *array = (GArray *) *bitmask; - int array_index; + const unsigned long *values = &g_array_index (array, unsigned long, 0); + int bit_num; - for (array_index = 0; array_index < array->len; array_index++) + COGL_FLAGS_FOREACH_START (values, array->len, bit_num) { - unsigned int mask = g_array_index (array, unsigned int, array_index); - int bit = 0; - - while (mask) - { - if (mask & 1) - func (array_index * sizeof (unsigned int) * 8 + bit, user_data); - - bit++; - mask >>= 1; - } + if (!func (bit_num, user_data)) + return; } + COGL_FLAGS_FOREACH_END; } else { - unsigned int mask = GPOINTER_TO_UINT (*bitmask) >> 1; - int bit = 0; + unsigned long mask = _cogl_bitmask_to_bits (bitmask); + int bit_num; - while (mask) + COGL_FLAGS_FOREACH_START (&mask, 1, bit_num) { - if (mask & 1) - func (bit, user_data); - - bit++; - mask >>= 1; + if (!func (bit_num, user_data)) + return; } + COGL_FLAGS_FOREACH_END; + } +} + +void +_cogl_bitmask_set_flags_array (const CoglBitmask *bitmask, + unsigned long *flags) +{ + const GArray *array = (const GArray *) *bitmask; + int i; + + for (i = 0; i < array->len; i++) + flags[i] |= g_array_index (array, unsigned long, i); +} + +int +_cogl_bitmask_popcount_in_array (const CoglBitmask *bitmask) +{ + const GArray *array = (const GArray *) *bitmask; + int pop = 0; + int i; + + for (i = 0; i < array->len; i++) + pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i)); + + return pop; +} + +int +_cogl_bitmask_popcount_upto_in_array (const CoglBitmask *bitmask, + int upto) +{ + const GArray *array = (const GArray *) *bitmask; + + if (upto >= array->len * sizeof (unsigned long) * 8) + return _cogl_bitmask_popcount_in_array (bitmask); + else + { + unsigned long top_mask; + int array_index = ARRAY_INDEX (upto); + int bit_index = BIT_INDEX (upto); + int pop = 0; + int i; + + for (i = 0; i < array_index; i++) + pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i)); + + top_mask = g_array_index (array, unsigned long, array_index); + + return pop + _cogl_util_popcountl (top_mask & ((1UL << bit_index) - 1)); } } diff --git a/cogl/cogl-bitmask.h b/cogl/cogl-bitmask.h index d3c36a4a..e37fc0f2 100644 --- a/cogl/cogl-bitmask.h +++ b/cogl/cogl-bitmask.h @@ -28,6 +28,7 @@ #define __COGL_BITMASK_H #include <glib.h> +#include "cogl-util.h" G_BEGIN_DECLS @@ -36,14 +37,17 @@ G_BEGIN_DECLS * be allocated on the stack but it must be initialised with * _cogl_bitmask_init() before use and then destroyed with * _cogl_bitmask_destroy(). A CoglBitmask will try to avoid allocating - * any memory unless more than 31 bits are needed. + * any memory unless more than the number of bits in a long - 1 bits + * are needed. * * Internally a CoglBitmask is a pointer. If the least significant bit * of the pointer is 1 then the rest of the bits are directly used as * part of the bitmask, otherwise it is a pointer to a GArray of * unsigned ints. This relies on the fact the g_malloc will return a * pointer aligned to at least two bytes (so that the least - * significant bit of the address is always 0) + * significant bit of the address is always 0). It also assumes that + * the size of a pointer is always greater than or equal to the size + * of a long (although there is a compile time assert to verify this). * * If the maximum possible bit number in the set is known at compile * time, it may make more sense to use the macros in cogl-flags.h @@ -52,13 +56,23 @@ G_BEGIN_DECLS typedef struct _CoglBitmaskImaginaryType *CoglBitmask; +/* These are internal helper macros */ +#define _cogl_bitmask_to_number(bitmask) \ + ((unsigned long) (*bitmask)) +#define _cogl_bitmask_to_bits(bitmask) \ + (_cogl_bitmask_to_number (bitmask) >> 1UL) +/* The least significant bit is set to mark that no array has been + allocated yet */ +#define _cogl_bitmask_from_bits(bits) \ + ((void *) ((((unsigned long) (bits)) << 1UL) | 1UL)) + /* Internal helper macro to determine whether this bitmask has a GArray allocated or whether the pointer is just used directly */ #define _cogl_bitmask_has_array(bitmask) \ - (!(GPOINTER_TO_UINT (*bitmask) & 1)) + (!(_cogl_bitmask_to_number (bitmask) & 1UL)) /* Number of bits we can use before needing to allocate an array */ -#define COGL_BITMASK_MAX_DIRECT_BITS (sizeof (unsigned int) * 8 - 1) +#define COGL_BITMASK_MAX_DIRECT_BITS (sizeof (unsigned long) * 8 - 1) /* * _cogl_bitmask_init: @@ -68,10 +82,8 @@ typedef struct _CoglBitmaskImaginaryType *CoglBitmask; * bitmask functions are called. Initially all of the values are * zero */ -/* Set the last significant bit to mark that no array has been - allocated yet */ #define _cogl_bitmask_init(bitmask) \ - G_STMT_START { *(bitmask) = GUINT_TO_POINTER (1); } G_STMT_END + G_STMT_START { *(bitmask) = _cogl_bitmask_from_bits (0); } G_STMT_END gboolean _cogl_bitmask_get_from_array (const CoglBitmask *bitmask, @@ -90,6 +102,17 @@ _cogl_bitmask_set_range_in_array (CoglBitmask *bitmask, void _cogl_bitmask_clear_all_in_array (CoglBitmask *bitmask); +void +_cogl_bitmask_set_flags_array (const CoglBitmask *bitmask, + unsigned long *flags); + +int +_cogl_bitmask_popcount_in_array (const CoglBitmask *bitmask); + +int +_cogl_bitmask_popcount_upto_in_array (const CoglBitmask *bitmask, + int upto); + /* * cogl_bitmask_set_bits: * @dst: The bitmask to modify @@ -114,7 +137,8 @@ void _cogl_bitmask_xor_bits (CoglBitmask *dst, const CoglBitmask *src); -typedef void (* CoglBitmaskForeachFunc) (int bit_num, gpointer user_data); +/* The foreach function can return FALSE to stop iteration */ +typedef gboolean (* CoglBitmaskForeachFunc) (int bit_num, void *user_data); /* * cogl_bitmask_foreach: @@ -127,7 +151,7 @@ typedef void (* CoglBitmaskForeachFunc) (int bit_num, gpointer user_data); void _cogl_bitmask_foreach (const CoglBitmask *bitmask, CoglBitmaskForeachFunc func, - gpointer user_data); + void *user_data); /* * _cogl_bitmask_get: @@ -144,7 +168,7 @@ _cogl_bitmask_get (const CoglBitmask *bitmask, unsigned int bit_num) else if (bit_num >= COGL_BITMASK_MAX_DIRECT_BITS) return FALSE; else - return !!(GPOINTER_TO_UINT (*bitmask) & (1 << (bit_num + 1))); + return !!(_cogl_bitmask_to_bits (bitmask) & (1UL << bit_num)); } /* @@ -162,11 +186,11 @@ _cogl_bitmask_set (CoglBitmask *bitmask, unsigned int bit_num, gboolean value) bit_num >= COGL_BITMASK_MAX_DIRECT_BITS) _cogl_bitmask_set_in_array (bitmask, bit_num, value); else if (value) - *bitmask = GUINT_TO_POINTER (GPOINTER_TO_UINT (*bitmask) | - (1 << (bit_num + 1))); + *bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) | + (1UL << bit_num)); else - *bitmask = GUINT_TO_POINTER (GPOINTER_TO_UINT (*bitmask) & - ~(1 << (bit_num + 1))); + *bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) & + ~(1UL << bit_num)); } /* @@ -186,11 +210,11 @@ _cogl_bitmask_set_range (CoglBitmask *bitmask, n_bits > COGL_BITMASK_MAX_DIRECT_BITS) _cogl_bitmask_set_range_in_array (bitmask, n_bits, value); else if (value) - *bitmask = GUINT_TO_POINTER (GPOINTER_TO_UINT (*bitmask) | - ~(~(unsigned int) 1 << n_bits)); + *bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) | + ~(~0UL << n_bits)); else - *bitmask = GUINT_TO_POINTER (GPOINTER_TO_UINT (*bitmask) & - ((~(unsigned int) 1 << n_bits) | 1)); + *bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) & + (~0UL << n_bits)); } /* @@ -218,10 +242,66 @@ _cogl_bitmask_clear_all (CoglBitmask *bitmask) if (_cogl_bitmask_has_array (bitmask)) _cogl_bitmask_clear_all_in_array (bitmask); else - *bitmask = GUINT_TO_POINTER (1); + *bitmask = _cogl_bitmask_from_bits (0); +} + +/* + * _cogl_bitmask_set_flags: + * @bitmask: A pointer to a bitmask + * @flags: An array of flags + * + * Bitwise or's the bits from @bitmask into the flags array (see + * cogl-flags) pointed to by @flags. + */ +static inline void +_cogl_bitmask_set_flags (const CoglBitmask *bitmask, + unsigned long *flags) +{ + if (_cogl_bitmask_has_array (bitmask)) + return _cogl_bitmask_set_flags_array (bitmask, flags); + else + flags[0] |= _cogl_bitmask_to_bits (bitmask); +} + +/* + * _cogl_bitmask_popcount: + * @bitmask: A pointer to a bitmask + * + * Counts the number of bits that are set in the bitmask. + * + * Return value: the number of bits set in @bitmask. + */ +static inline int +_cogl_bitmask_popcount (const CoglBitmask *bitmask) +{ + return (_cogl_bitmask_has_array (bitmask) ? + _cogl_bitmask_popcount_in_array (bitmask) : + _cogl_util_popcountl (_cogl_bitmask_to_bits (bitmask))); +} + +/* + * _cogl_bitmask_popcount: + * @Bitmask: A pointer to a bitmask + * @upto: The maximum bit index to consider + * + * Counts the number of bits that are set and have an index which is + * less than @upto. + * + * Return value: the number of bits set in @bitmask that are less than @upto. + */ +static inline int +_cogl_bitmask_popcount_upto (const CoglBitmask *bitmask, + int upto) +{ + if (_cogl_bitmask_has_array (bitmask)) + return _cogl_bitmask_popcount_upto_in_array (bitmask, upto); + else if (upto >= COGL_BITMASK_MAX_DIRECT_BITS) + return _cogl_util_popcountl (_cogl_bitmask_to_bits (bitmask)); + else + return _cogl_util_popcountl (_cogl_bitmask_to_bits (bitmask) & + ((1UL << upto) - 1)); } G_END_DECLS #endif /* __COGL_BITMASK_H */ - diff --git a/cogl/cogl-boxed-value.c b/cogl/cogl-boxed-value.c new file mode 100644 index 00000000..b2cb3f32 --- /dev/null +++ b/cogl/cogl-boxed-value.c @@ -0,0 +1,336 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include "cogl-boxed-value.h" +#include "cogl-context-private.h" + +gboolean +_cogl_boxed_value_equal (const CoglBoxedValue *bva, + const CoglBoxedValue *bvb) +{ + const void *pa, *pb; + + if (bva->type != bvb->type) + return FALSE; + + switch (bva->type) + { + case COGL_BOXED_NONE: + return TRUE; + + case COGL_BOXED_INT: + if (bva->size != bvb->size || bva->count != bvb->count) + return FALSE; + + if (bva->count == 1) + { + pa = bva->v.int_value; + pb = bvb->v.int_value; + } + else + { + pa = bva->v.int_array; + pb = bvb->v.int_array; + } + + return !memcmp (pa, pb, sizeof (int) * bva->size * bva->count); + + case COGL_BOXED_FLOAT: + if (bva->size != bvb->size || bva->count != bvb->count) + return FALSE; + + if (bva->count == 1) + { + pa = bva->v.float_value; + pb = bvb->v.float_value; + } + else + { + pa = bva->v.float_array; + pb = bvb->v.float_array; + } + + return !memcmp (pa, pb, sizeof (float) * bva->size * bva->count); + + case COGL_BOXED_MATRIX: + if (bva->size != bvb->size || + bva->count != bvb->count || + bva->transpose != bvb->transpose) + return FALSE; + + if (bva->count == 1) + { + pa = bva->v.matrix; + pb = bvb->v.matrix; + } + else + { + pa = bva->v.array; + pb = bvb->v.array; + } + + return !memcmp (pa, pb, + sizeof (float) * bva->size * bva->size * bva->count); + } + + g_warn_if_reached (); + + return FALSE; +} + +static void +_cogl_boxed_value_set_x (CoglBoxedValue *bv, + int size, + int count, + CoglBoxedType type, + gsize value_size, + gconstpointer value, + gboolean transpose) +{ + if (count == 1) + { + if (bv->count > 1) + g_free (bv->v.array); + + memcpy (bv->v.float_value, value, value_size); + } + else + { + if (bv->count > 1) + { + if (bv->count != count || + bv->size != size || + bv->type != type) + { + g_free (bv->v.array); + bv->v.array = g_malloc (count * value_size); + } + } + else + bv->v.array = g_malloc (count * value_size); + + memcpy (bv->v.array, value, count * value_size); + } + + bv->type = type; + bv->size = size; + bv->count = count; + bv->transpose = transpose; +} + +void +_cogl_boxed_value_set_1f (CoglBoxedValue *bv, + float value) +{ + _cogl_boxed_value_set_x (bv, + 1, 1, COGL_BOXED_FLOAT, + sizeof (float), &value, FALSE); +} + +void +_cogl_boxed_value_set_1i (CoglBoxedValue *bv, + int value) +{ + _cogl_boxed_value_set_x (bv, + 1, 1, COGL_BOXED_INT, + sizeof (int), &value, FALSE); +} + +void +_cogl_boxed_value_set_float (CoglBoxedValue *bv, + int n_components, + int count, + const float *value) +{ + _cogl_boxed_value_set_x (bv, + n_components, count, + COGL_BOXED_FLOAT, + sizeof (float) * n_components, value, FALSE); +} + +void +_cogl_boxed_value_set_int (CoglBoxedValue *bv, + int n_components, + int count, + const int *value) +{ + _cogl_boxed_value_set_x (bv, + n_components, count, + COGL_BOXED_INT, + sizeof (int) * n_components, value, FALSE); +} + +void +_cogl_boxed_value_set_matrix (CoglBoxedValue *bv, + int dimensions, + int count, + gboolean transpose, + const float *value) +{ + _cogl_boxed_value_set_x (bv, + dimensions, count, + COGL_BOXED_MATRIX, + sizeof (float) * dimensions * dimensions, + value, + transpose); +} + +void +_cogl_boxed_value_copy (CoglBoxedValue *dst, + const CoglBoxedValue *src) +{ + *dst = *src; + + if (src->count > 1) + { + switch (src->type) + { + case COGL_BOXED_NONE: + break; + + case COGL_BOXED_INT: + dst->v.int_array = g_memdup (src->v.int_array, + src->size * src->count * sizeof (int)); + break; + + case COGL_BOXED_FLOAT: + dst->v.float_array = g_memdup (src->v.float_array, + src->size * + src->count * + sizeof (float)); + break; + + case COGL_BOXED_MATRIX: + dst->v.float_array = g_memdup (src->v.float_array, + src->size * src->size * + src->count * sizeof (float)); + break; + } + } +} + +void +_cogl_boxed_value_destroy (CoglBoxedValue *bv) +{ + if (bv->count > 1) + g_free (bv->v.array); +} + +void +_cogl_boxed_value_set_uniform (CoglContext *ctx, + GLint location, + const CoglBoxedValue *value) +{ + switch (value->type) + { + case COGL_BOXED_NONE: + break; + + case COGL_BOXED_INT: + { + const int *ptr; + + if (value->count == 1) + ptr = value->v.int_value; + else + ptr = value->v.int_array; + + switch (value->size) + { + case 1: + GE( ctx, glUniform1iv (location, value->count, ptr) ); + break; + case 2: + GE( ctx, glUniform2iv (location, value->count, ptr) ); + break; + case 3: + GE( ctx, glUniform3iv (location, value->count, ptr) ); + break; + case 4: + GE( ctx, glUniform4iv (location, value->count, ptr) ); + break; + } + } + break; + + case COGL_BOXED_FLOAT: + { + const float *ptr; + + if (value->count == 1) + ptr = value->v.float_value; + else + ptr = value->v.float_array; + + switch (value->size) + { + case 1: + GE( ctx, glUniform1fv (location, value->count, ptr) ); + break; + case 2: + GE( ctx, glUniform2fv (location, value->count, ptr) ); + break; + case 3: + GE( ctx, glUniform3fv (location, value->count, ptr) ); + break; + case 4: + GE( ctx, glUniform4fv (location, value->count, ptr) ); + break; + } + } + break; + + case COGL_BOXED_MATRIX: + { + const float *ptr; + + if (value->count == 1) + ptr = value->v.matrix; + else + ptr = value->v.float_array; + + switch (value->size) + { + case 2: + GE( ctx, glUniformMatrix2fv (location, value->count, + value->transpose, ptr) ); + break; + case 3: + GE( ctx, glUniformMatrix3fv (location, value->count, + value->transpose, ptr) ); + break; + case 4: + GE( ctx, glUniformMatrix4fv (location, value->count, + value->transpose, ptr) ); + break; + } + } + break; + } +} diff --git a/cogl/cogl-boxed-value.h b/cogl/cogl-boxed-value.h new file mode 100644 index 00000000..d9dd45a0 --- /dev/null +++ b/cogl/cogl-boxed-value.h @@ -0,0 +1,111 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2011 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * + */ + +#ifndef __COGL_BOXED_VALUE_H +#define __COGL_BOXED_VALUE_H + +#include <glib.h> + +#include "cogl-context.h" + +typedef enum { + COGL_BOXED_NONE, + COGL_BOXED_INT, + COGL_BOXED_FLOAT, + COGL_BOXED_MATRIX +} CoglBoxedType; + +typedef struct _CoglBoxedValue +{ + CoglBoxedType type; + int size, count; + gboolean transpose; + + union { + float float_value[4]; + int int_value[4]; + float matrix[16]; + float *float_array; + int *int_array; + void *array; + } v; +} CoglBoxedValue; + +#define _cogl_boxed_value_init(bv) \ + G_STMT_START { \ + CoglBoxedValue *_bv = (bv); \ + _bv->type = COGL_BOXED_NONE; \ + _bv->count = 1; \ + } G_STMT_END + +gboolean +_cogl_boxed_value_equal (const CoglBoxedValue *bva, + const CoglBoxedValue *bvb); + +void +_cogl_boxed_value_set_1f (CoglBoxedValue *bv, + float value); + +void +_cogl_boxed_value_set_1i (CoglBoxedValue *bv, + int value); + +void +_cogl_boxed_value_set_float (CoglBoxedValue *bv, + int n_components, + int count, + const float *value); + +void +_cogl_boxed_value_set_int (CoglBoxedValue *bv, + int n_components, + int count, + const int *value); + +void +_cogl_boxed_value_set_matrix (CoglBoxedValue *bv, + int dimensions, + int count, + gboolean transpose, + const float *value); + +/* + * _cogl_boxed_value_copy: + * @dst: The destination boxed value + * @src: The source boxed value + * + * This copies @src to @dst. It is assumed that @dst is initialised. + */ +void +_cogl_boxed_value_copy (CoglBoxedValue *dst, + const CoglBoxedValue *src); + +void +_cogl_boxed_value_destroy (CoglBoxedValue *bv); + +void +_cogl_boxed_value_set_uniform (CoglContext *ctx, + int location, + const CoglBoxedValue *value); + +#endif /* __COGL_BOXED_VALUE_H */ diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h index 3b40b36e..f0d1655e 100644 --- a/cogl/cogl-context-private.h +++ b/cogl/cogl-context-private.h @@ -63,7 +63,7 @@ struct _CoglContext const CoglTextureDriver *texture_driver; /* Features cache */ - unsigned int features[COGL_FLAGS_N_INTS_FOR_SIZE (_COGL_N_FEATURE_IDS)]; + unsigned long features[COGL_FLAGS_N_LONGS_FOR_SIZE (_COGL_N_FEATURE_IDS)]; CoglFeatureFlags feature_flags; /* legacy/deprecated feature flags */ CoglPrivateFeatureFlags private_feature_flags; @@ -254,10 +254,22 @@ struct _CoglContext CoglXlibTrapState *trap_state; #endif - unsigned int winsys_features - [COGL_FLAGS_N_INTS_FOR_SIZE (COGL_WINSYS_FEATURE_N_FEATURES)]; + unsigned long winsys_features + [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_WINSYS_FEATURE_N_FEATURES)]; void *winsys; + /* Array of names of uniforms. These are used like quarks to give a + unique number to each uniform name except that we ensure that + they increase sequentially so that we can use the id as an index + into a bitfield representing the uniforms that a pipeline + overrides from its parent. */ + GPtrArray *uniform_names; + /* A hash table to quickly get an index given an existing name. The + name strings are owned by the uniform_names array. The values are + the uniform location cast to a pointer. */ + GHashTable *uniform_name_hash; + int n_uniform_names; + /* This defines a list of function pointers that Cogl uses from either GL or GLES. All functions are accessed indirectly through these pointers rather than linking to them directly */ diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index b8296ece..62a04837 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -221,6 +221,11 @@ cogl_context_new (CoglDisplay *display, g_assert_not_reached (); } + context->uniform_names = + g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); + context->uniform_name_hash = g_hash_table_new (g_str_hash, g_str_equal); + context->n_uniform_names = 0; + /* Initialise the driver specific state */ _cogl_init_feature_overrides (context); @@ -478,8 +483,12 @@ _cogl_context_free (CoglContext *context) cogl_pipeline_cache_free (context->pipeline_cache); + _cogl_destroy_texture_units (); + g_ptr_array_free (context->uniform_names, TRUE); + g_hash_table_destroy (context->uniform_name_hash); + g_byte_array_free (context->buffer_map_fallback_array, TRUE); cogl_object_unref (context->display); diff --git a/cogl/cogl-debug.c b/cogl/cogl-debug.c index 2e1fb2e9..3651dffd 100644 --- a/cogl/cogl-debug.c +++ b/cogl/cogl-debug.c @@ -83,7 +83,7 @@ static const GDebugKey cogl_behavioural_debug_keys[] = { static const int n_cogl_behavioural_debug_keys = G_N_ELEMENTS (cogl_behavioural_debug_keys); -unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS]; +unsigned long _cogl_debug_flags[COGL_DEBUG_N_LONGS]; GHashTable *_cogl_debug_instances; static void @@ -92,36 +92,54 @@ _cogl_parse_debug_string_for_keys (const char *value, const GDebugKey *keys, unsigned int nkeys) { - int int_num, key_num; + int long_num, key_num; /* g_parse_debug_string expects the value field in GDebugKey to be a - mask in a guint but we may have multiple guints so we need to - build a separate array for each possible guint */ + mask in a guint but the flags is stored in an array of multiple + longs so we need to build a separate array for each possible + guint */ - for (int_num = 0; int_num < COGL_DEBUG_N_INTS; int_num++) + for (long_num = 0; long_num < COGL_DEBUG_N_LONGS; long_num++) { - GDebugKey keys_for_int[sizeof (unsigned int) * 8]; - unsigned int mask_for_int; - int nkeys_for_int = 0; + int int_num; - for (key_num = 0; key_num < nkeys; key_num++) - if (COGL_FLAGS_GET_INDEX (keys[key_num].value) == int_num) - { - keys_for_int[nkeys_for_int] = keys[key_num]; - keys_for_int[nkeys_for_int].value = - COGL_FLAGS_GET_MASK (keys[key_num].value); - nkeys_for_int++; - } - - if (nkeys_for_int > 0) + for (int_num = 0; + int_num < sizeof (unsigned long) / sizeof (unsigned int); + int_num++) { - mask_for_int = g_parse_debug_string (value, - keys_for_int, - nkeys_for_int); - if (enable) - _cogl_debug_flags[int_num] |= mask_for_int; - else - _cogl_debug_flags[int_num] &= ~mask_for_int; + GDebugKey keys_for_int[sizeof (unsigned int) * 8]; + int nkeys_for_int = 0; + + for (key_num = 0; key_num < nkeys; key_num++) + { + int long_index = COGL_FLAGS_GET_INDEX (keys[key_num].value); + int int_index = (keys[key_num].value % + (sizeof (unsigned long) * 8) / + (sizeof (unsigned int) * 8)); + + if (long_index == long_num && int_index == int_num) + { + keys_for_int[nkeys_for_int] = keys[key_num]; + keys_for_int[nkeys_for_int].value = + COGL_FLAGS_GET_MASK (keys[key_num].value) >> + (int_num * sizeof (unsigned int) * 8); + nkeys_for_int++; + } + } + + if (nkeys_for_int > 0) + { + unsigned long mask = + ((unsigned long) g_parse_debug_string (value, + keys_for_int, + nkeys_for_int)) << + (int_num * sizeof (unsigned int) * 8); + + if (enable) + _cogl_debug_flags[long_num] |= mask; + else + _cogl_debug_flags[long_num] &= ~mask; + } } } } diff --git a/cogl/cogl-debug.h b/cogl/cogl-debug.h index 4fe20cdb..a6edbb34 100644 --- a/cogl/cogl-debug.h +++ b/cogl/cogl-debug.h @@ -82,9 +82,9 @@ typedef enum { #ifdef COGL_ENABLE_DEBUG -#define COGL_DEBUG_N_INTS COGL_FLAGS_N_INTS_FOR_SIZE (COGL_DEBUG_N_FLAGS) +#define COGL_DEBUG_N_LONGS COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_DEBUG_N_FLAGS) -COGL_EXP extern unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS]; +COGL_EXP extern unsigned long _cogl_debug_flags[COGL_DEBUG_N_LONGS]; COGL_EXP extern GHashTable *_cogl_debug_instances; #define COGL_DEBUG_ENABLED(flag) \ diff --git a/cogl/cogl-fixed.c b/cogl/cogl-fixed.c index 7be9c3d9..f56c28e3 100644 --- a/cogl/cogl-fixed.c +++ b/cogl/cogl-fixed.c @@ -27,6 +27,9 @@ #include "config.h" #endif +#include <glib-object.h> +#include <gobject/gvaluecollector.h> + #include "cogl-fixed.h" /* pre-computed sin table for 1st quadrant @@ -948,3 +951,147 @@ cogl_fixed_cos (CoglFixed angle) return cogl_fixed_sin (a); } + +/* GType */ + +static GTypeInfo _info = { + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL, +}; + +static GTypeFundamentalInfo _finfo = { 0, }; + +static void +cogl_value_init_fixed (GValue *value) +{ + value->data[0].v_int = 0; +} + +static void +cogl_value_copy_fixed (const GValue *src, + GValue *dest) +{ + dest->data[0].v_int = src->data[0].v_int; +} + +static char * +cogl_value_collect_fixed (GValue *value, + unsigned int n_collect_values, + GTypeCValue *collect_values, + unsigned int collect_flags) +{ + value->data[0].v_int = collect_values[0].v_int; + + return NULL; +} + +static char * +cogl_value_lcopy_fixed (const GValue *value, + unsigned int n_collect_values, + GTypeCValue *collect_values, + unsigned int collect_flags) +{ + gint32 *fixed_p = collect_values[0].v_pointer; + + if (!fixed_p) + return g_strdup_printf ("value location for '%s' passed as NULL", + G_VALUE_TYPE_NAME (value)); + + *fixed_p = value->data[0].v_int; + + return NULL; +} + +static void +cogl_value_transform_fixed_int (const GValue *src, + GValue *dest) +{ + dest->data[0].v_int = COGL_FIXED_TO_INT (src->data[0].v_int); +} + +static void +cogl_value_transform_fixed_double (const GValue *src, + GValue *dest) +{ + dest->data[0].v_double = COGL_FIXED_TO_DOUBLE (src->data[0].v_int); +} + +static void +cogl_value_transform_fixed_float (const GValue *src, + GValue *dest) +{ + dest->data[0].v_float = COGL_FIXED_TO_FLOAT (src->data[0].v_int); +} + +static void +cogl_value_transform_int_fixed (const GValue *src, + GValue *dest) +{ + dest->data[0].v_int = COGL_FIXED_FROM_INT (src->data[0].v_int); +} + +static void +cogl_value_transform_double_fixed (const GValue *src, + GValue *dest) +{ + dest->data[0].v_int = COGL_FIXED_FROM_DOUBLE (src->data[0].v_double); +} + +static void +cogl_value_transform_float_fixed (const GValue *src, + GValue *dest) +{ + dest->data[0].v_int = COGL_FIXED_FROM_FLOAT (src->data[0].v_float); +} + + +static const GTypeValueTable _cogl_fixed_value_table = { + cogl_value_init_fixed, + NULL, + cogl_value_copy_fixed, + NULL, + "i", + cogl_value_collect_fixed, + "p", + cogl_value_lcopy_fixed +}; + +GType +cogl_fixed_get_type (void) +{ + static GType _cogl_fixed_type = 0; + + if (G_UNLIKELY (_cogl_fixed_type == 0)) + { + _info.value_table = & _cogl_fixed_value_table; + _cogl_fixed_type = + g_type_register_fundamental (g_type_fundamental_next (), + g_intern_static_string ("CoglFixed"), + &_info, &_finfo, 0); + + g_value_register_transform_func (_cogl_fixed_type, G_TYPE_INT, + cogl_value_transform_fixed_int); + g_value_register_transform_func (G_TYPE_INT, _cogl_fixed_type, + cogl_value_transform_int_fixed); + + g_value_register_transform_func (_cogl_fixed_type, G_TYPE_FLOAT, + cogl_value_transform_fixed_float); + g_value_register_transform_func (G_TYPE_FLOAT, _cogl_fixed_type, + cogl_value_transform_float_fixed); + + g_value_register_transform_func (_cogl_fixed_type, G_TYPE_DOUBLE, + cogl_value_transform_fixed_double); + g_value_register_transform_func (G_TYPE_DOUBLE, _cogl_fixed_type, + cogl_value_transform_double_fixed); + } + + return _cogl_fixed_type; +} diff --git a/cogl/cogl-flags.h b/cogl/cogl-flags.h index af07532f..bf5eadd4 100644 --- a/cogl/cogl-flags.h +++ b/cogl/cogl-flags.h @@ -29,6 +29,8 @@ #include <glib.h> +#include "cogl-util.h" + G_BEGIN_DECLS /* These are macros used to implement a fixed-size array of bits. This @@ -36,36 +38,31 @@ G_BEGIN_DECLS that will be set is known at compile time, for example when setting for recording a set of known available features */ -/* The bits are stored in an array of unsigned ints. It would probably - make sense to use unsigned long instead because then on 64-bit - systems where it can handle 64-bits just as easily and it can test - more bits. However GDebugKey uses a guint for the mask and we need - to fit the masks into this */ - -/* To use these macros, you would typically have an enum defining the - available bits with an extra last enum to define the maximum - value. Then to store the flags you would declare an array of - unsigned ints sized using COGL_FLAGS_N_INTS_FOR_SIZE, eg: +/* The bits are stored in an array of unsigned longs. To use these + macros, you would typically have an enum defining the available + bits with an extra last enum to define the maximum value. Then to + store the flags you would declare an array of unsigned longs sized + using COGL_FLAGS_N_LONGS_FOR_SIZE, eg: typedef enum { FEATURE_A, FEATURE_B, FEATURE_C, N_FEATURES } Features; - unsigned int feature_flags[COGL_FLAGS_N_INTS_FOR_SIZE (N_FEATURES)]; + unsigned long feature_flags[COGL_FLAGS_N_LONGS_FOR_SIZE (N_FEATURES)]; */ -#define COGL_FLAGS_N_INTS_FOR_SIZE(size) \ +#define COGL_FLAGS_N_LONGS_FOR_SIZE(size) \ (((size) + \ - (sizeof (unsigned int) * 8 - 1)) \ - / (sizeof (unsigned int) * 8)) + (sizeof (unsigned long) * 8 - 1)) \ + / (sizeof (unsigned long) * 8)) /* @flag is expected to be constant so these should result in a constant expression. This means that setting a flag is equivalent to just setting in a bit in a global variable at a known location */ #define COGL_FLAGS_GET_INDEX(flag) \ - ((flag) / (sizeof (unsigned int) * 8)) + ((flag) / (sizeof (unsigned long) * 8)) #define COGL_FLAGS_GET_MASK(flag) \ - (1U << ((unsigned int) (flag) & \ - (sizeof (unsigned int) * 8 - 1))) + (1UL << ((unsigned long) (flag) & \ + (sizeof (unsigned long) * 8 - 1))) #define COGL_FLAGS_GET(array, flag) \ (!!((array)[COGL_FLAGS_GET_INDEX (flag)] & \ @@ -83,6 +80,40 @@ G_BEGIN_DECLS ~COGL_FLAGS_GET_MASK (flag)); \ } G_STMT_END +/* Macros to help iterate an array of flags. It should be used like + * this: + * + * int n_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (...); + * unsigned long flags[n_longs]; + * int bit_num; + * + * COGL_FLAGS_FOREACH_START (flags, n_longs, bit_num) + * { + * do_something_with_the_bit (bit_num); + * } + * COGL_FLAGS_FOREACH_END; + */ +#define COGL_FLAGS_FOREACH_START(array, n_longs, bit) \ + G_STMT_START { \ + const unsigned long *_p = (array); \ + int _n_longs = (n_longs); \ + int _i; \ + \ + for (_i = 0; _i < _n_longs; _i++) \ + { \ + unsigned long _mask = *(_p++); \ + \ + (bit) = _i * sizeof (unsigned long) * 8 - 1; \ + \ + while (_mask) \ + { \ + int _next_bit = _cogl_util_ffsl (_mask); \ + (bit) += _next_bit; \ + _mask >>= _next_bit; + +#define COGL_FLAGS_FOREACH_END \ + } } } G_STMT_END + G_END_DECLS #endif /* __COGL_FLAGS_H */ diff --git a/cogl/cogl-internal.h b/cogl/cogl-internal.h index 946f8bca..6d001375 100644 --- a/cogl/cogl-internal.h +++ b/cogl/cogl-internal.h @@ -32,29 +32,6 @@ #include <X11/Xutil.h> #endif -typedef enum { - COGL_BOXED_NONE, - COGL_BOXED_INT, - COGL_BOXED_FLOAT, - COGL_BOXED_MATRIX -} CoglBoxedType; - -typedef struct _CoglBoxedValue -{ - CoglBoxedType type; - int size, count; - gboolean transpose; - - union { - float float_value[4]; - int int_value[4]; - float matrix[16]; - float *float_array; - int *int_array; - void *array; - } v; -} CoglBoxedValue; - #ifdef COGL_GL_DEBUG const char * diff --git a/cogl/cogl-matrix.c b/cogl/cogl-matrix.c index abb0a926..396017c5 100644 --- a/cogl/cogl-matrix.c +++ b/cogl/cogl-matrix.c @@ -1689,7 +1689,6 @@ cogl_matrix_init_from_quaternion (CoglMatrix *matrix, _cogl_matrix_init_from_quaternion (matrix, quaternion); } -#if 0 /* * Transpose a float matrix. */ @@ -1713,7 +1712,6 @@ _cogl_matrix_util_transposef (float to[16], const float from[16]) to[14] = from[11]; to[15] = from[15]; } -#endif void cogl_matrix_view_2d_in_frustum (CoglMatrix *matrix, @@ -2122,3 +2120,18 @@ cogl_matrix_look_at (CoglMatrix *matrix, cogl_matrix_multiply (matrix, matrix, &tmp); } + +void +cogl_matrix_transpose (CoglMatrix *matrix) +{ + float new_values[16]; + + /* We don't need to do anything if the matrix is the identity matrix */ + if (!(matrix->flags & MAT_DIRTY_TYPE) && + matrix->type == COGL_MATRIX_TYPE_IDENTITY) + return; + + _cogl_matrix_util_transposef (new_values, cogl_matrix_get_array (matrix)); + + cogl_matrix_init_from_array (matrix, new_values); +} diff --git a/cogl/cogl-matrix.h b/cogl/cogl-matrix.h index 14e92a3b..0bb3e75e 100644 --- a/cogl/cogl-matrix.h +++ b/cogl/cogl-matrix.h @@ -653,6 +653,18 @@ cogl_matrix_project_points (const CoglMatrix *matrix, gboolean cogl_matrix_is_identity (const CoglMatrix *matrix); +/** + * cogl_matrix_transpose: + * @matrix: A #CoglMatrix + * + * Replaces @matrix with its transpose. Ie, every element (i,j) in the + * new matrix is taken from element (j,i) in the old matrix. + * + * Since: 1.10 + */ +void +cogl_matrix_transpose (CoglMatrix *matrix); + #ifdef _COGL_SUPPORTS_GTYPE_INTEGRATION #define COGL_GTYPE_TYPE_MATRIX (cogl_gtype_matrix_get_type ()) diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h index 4d045364..a6100a8c 100644 --- a/cogl/cogl-pipeline-private.h +++ b/cogl/cogl-pipeline-private.h @@ -36,6 +36,7 @@ #include "cogl-profile.h" #include "cogl-queue.h" #include "cogl-internal.h" +#include "cogl-boxed-value.h" #include <glib.h> @@ -166,6 +167,7 @@ typedef enum COGL_PIPELINE_STATE_POINT_SIZE_INDEX, COGL_PIPELINE_STATE_LOGIC_OPS_INDEX, COGL_PIPELINE_STATE_CULL_FACE_INDEX, + COGL_PIPELINE_STATE_UNIFORMS_INDEX, /* non-sparse */ COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX, @@ -213,6 +215,8 @@ typedef enum _CoglPipelineState 1L<<COGL_PIPELINE_STATE_LOGIC_OPS_INDEX, COGL_PIPELINE_STATE_CULL_FACE = 1L<<COGL_PIPELINE_STATE_CULL_FACE_INDEX, + COGL_PIPELINE_STATE_UNIFORMS = + 1L<<COGL_PIPELINE_STATE_UNIFORMS_INDEX, COGL_PIPELINE_STATE_REAL_BLEND_ENABLE = 1L<<COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX, @@ -248,7 +252,8 @@ typedef enum _CoglPipelineState COGL_PIPELINE_STATE_FOG | \ COGL_PIPELINE_STATE_POINT_SIZE | \ COGL_PIPELINE_STATE_LOGIC_OPS | \ - COGL_PIPELINE_STATE_CULL_FACE) + COGL_PIPELINE_STATE_CULL_FACE | \ + COGL_PIPELINE_STATE_UNIFORMS) #define COGL_PIPELINE_STATE_MULTI_PROPERTY \ (COGL_PIPELINE_STATE_LAYERS | \ @@ -257,7 +262,8 @@ typedef enum _CoglPipelineState COGL_PIPELINE_STATE_DEPTH | \ COGL_PIPELINE_STATE_FOG | \ COGL_PIPELINE_STATE_LOGIC_OPS | \ - COGL_PIPELINE_STATE_CULL_FACE) + COGL_PIPELINE_STATE_CULL_FACE | \ + COGL_PIPELINE_STATE_UNIFORMS) #define COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN \ (COGL_PIPELINE_STATE_LAYERS | \ @@ -335,6 +341,20 @@ typedef struct typedef struct { + CoglBitmask override_mask; + + /* This is an array of values. Only the uniforms that have a bit set + in override_mask have a corresponding value here. The uniform's + location is implicit from the order in this array */ + CoglBoxedValue *override_values; + + /* Uniforms that have been modified since this pipeline was last + flushed */ + CoglBitmask changed_mask; +} CoglPipelineUniformsState; + +typedef struct +{ CoglPipelineLightingState lighting_state; CoglPipelineAlphaFuncState alpha_state; CoglPipelineBlendState blend_state; @@ -344,6 +364,7 @@ typedef struct float point_size; CoglPipelineLogicOpsState logic_ops_state; CoglPipelineCullFaceState cull_face_state; + CoglPipelineUniformsState uniforms_state; } CoglPipelineBigState; typedef enum diff --git a/cogl/cogl-pipeline-progend-glsl.c b/cogl/cogl-pipeline-progend-glsl.c index 0d83ed60..c612d735 100644 --- a/cogl/cogl-pipeline-progend-glsl.c +++ b/cogl/cogl-pipeline-progend-glsl.c @@ -29,6 +29,8 @@ #include "config.h" #endif +#include <string.h> + #include "cogl-util.h" #include "cogl-context-private.h" #include "cogl-pipeline-private.h" @@ -44,6 +46,7 @@ #include "cogl-pipeline-fragend-glsl-private.h" #include "cogl-pipeline-vertend-glsl-private.h" #include "cogl-pipeline-cache.h" +#include "cogl-pipeline-state-private.h" #ifdef HAVE_COGL_GLES2 @@ -140,6 +143,11 @@ typedef struct * so know if we need to update all of the uniforms */ CoglPipeline *last_used_for_pipeline; + /* Array of GL uniform locations indexed by Cogl's uniform + location. We are careful only to allocated this array if a custom + uniform is actually set */ + GArray *uniform_locations; + UnitState *unit_state; } CoglPipelineProgramState; @@ -151,6 +159,8 @@ get_program_state (CoglPipeline *pipeline) return cogl_object_get_user_data (COGL_OBJECT (pipeline), &program_state_key); } +#define UNIFORM_LOCATION_UNKNOWN -2 + #ifdef HAVE_COGL_GLES2 #define ATTRIBUTE_LOCATION_UNKNOWN -2 @@ -309,6 +319,7 @@ program_state_new (int n_layers) program_state->program = 0; program_state->n_tex_coord_attribs = 0; program_state->unit_state = g_new (UnitState, n_layers); + program_state->uniform_locations = NULL; #ifdef HAVE_COGL_GLES2 program_state->tex_coord_attribute_locations = NULL; program_state->flushed_modelview_stack = NULL; @@ -349,6 +360,9 @@ destroy_program_state (void *user_data, g_free (program_state->unit_state); + if (program_state->uniform_locations) + g_array_free (program_state->uniform_locations, TRUE); + g_slice_free (CoglPipelineProgramState, program_state); } } @@ -539,6 +553,167 @@ update_builtin_uniforms (CoglPipeline *pipeline, #endif /* HAVE_COGL_GLES2 */ +typedef struct +{ + CoglPipelineProgramState *program_state; + unsigned long *uniform_differences; + int n_differences; + CoglContext *ctx; + const CoglBoxedValue *values; + int value_index; +} FlushUniformsClosure; + +static gboolean +flush_uniform_cb (int uniform_num, void *user_data) +{ + FlushUniformsClosure *data = user_data; + + if (COGL_FLAGS_GET (data->uniform_differences, uniform_num)) + { + GArray *uniform_locations; + GLint uniform_location; + + if (data->program_state->uniform_locations == NULL) + data->program_state->uniform_locations = + g_array_new (FALSE, FALSE, sizeof (GLint)); + + uniform_locations = data->program_state->uniform_locations; + + if (uniform_locations->len <= uniform_num) + { + unsigned int old_len = uniform_locations->len; + + g_array_set_size (uniform_locations, uniform_num + 1); + + while (old_len <= uniform_num) + { + g_array_index (uniform_locations, GLint, old_len) = + UNIFORM_LOCATION_UNKNOWN; + old_len++; + } + } + + uniform_location = g_array_index (uniform_locations, GLint, uniform_num); + + if (uniform_location == UNIFORM_LOCATION_UNKNOWN) + { + const char *uniform_name = + g_ptr_array_index (data->ctx->uniform_names, uniform_num); + + uniform_location = + data->ctx->glGetUniformLocation (data->program_state->program, + uniform_name); + g_array_index (uniform_locations, GLint, uniform_num) = + uniform_location; + } + + if (uniform_location != -1) + _cogl_boxed_value_set_uniform (data->ctx, + uniform_location, + data->values + data->value_index); + + data->n_differences--; + COGL_FLAGS_SET (data->uniform_differences, uniform_num, FALSE); + } + + data->value_index++; + + return data->n_differences > 0; +} + +static void +_cogl_pipeline_progend_glsl_flush_uniforms (CoglPipeline *pipeline, + CoglPipelineProgramState * + program_state, + GLuint gl_program, + gboolean program_changed) +{ + CoglPipelineUniformsState *uniforms_state; + FlushUniformsClosure data; + int n_uniform_longs; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS) + uniforms_state = &pipeline->big_state->uniforms_state; + else + uniforms_state = NULL; + + data.program_state = program_state; + data.ctx = ctx; + + n_uniform_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (ctx->n_uniform_names); + + data.uniform_differences = g_newa (unsigned long, n_uniform_longs); + + /* Try to find a common ancestor for the values that were already + flushed on the pipeline that this program state was last used for + so we can avoid flushing those */ + + if (program_changed || program_state->last_used_for_pipeline == NULL) + { + if (program_changed) + { + /* The program has changed so all of the uniform locations + are invalid */ + if (program_state->uniform_locations) + g_array_set_size (program_state->uniform_locations, 0); + } + + /* We need to flush everything so mark all of the uniforms as + dirty */ + memset (data.uniform_differences, 0xff, + n_uniform_longs * sizeof (unsigned long)); + data.n_differences = G_MAXINT; + } + else if (program_state->last_used_for_pipeline) + { + int i; + + memset (data.uniform_differences, 0, + n_uniform_longs * sizeof (unsigned long)); + _cogl_pipeline_compare_uniform_differences + (data.uniform_differences, + program_state->last_used_for_pipeline, + pipeline); + + /* We need to be sure to flush any uniforms that have changed + since the last flush */ + if (uniforms_state) + _cogl_bitmask_set_flags (&uniforms_state->changed_mask, + data.uniform_differences); + + /* Count the number of differences. This is so we can stop early + when we've flushed all of them */ + data.n_differences = 0; + + for (i = 0; i < n_uniform_longs; i++) + data.n_differences += + _cogl_util_popcountl (data.uniform_differences[i]); + } + + while (pipeline && data.n_differences > 0) + { + if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS) + { + const CoglPipelineUniformsState *parent_uniforms_state = + &pipeline->big_state->uniforms_state; + + data.values = parent_uniforms_state->override_values; + data.value_index = 0; + + _cogl_bitmask_foreach (&parent_uniforms_state->override_mask, + flush_uniform_cb, + &data); + } + + pipeline = _cogl_pipeline_get_parent (pipeline); + } + + if (uniforms_state) + _cogl_bitmask_clear_all (&uniforms_state->changed_mask); +} + static void _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline, unsigned long pipelines_difference, @@ -730,6 +905,11 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline, } #endif + _cogl_pipeline_progend_glsl_flush_uniforms (pipeline, + program_state, + gl_program, + program_changed); + if (user_program) _cogl_program_flush_uniforms (user_program, gl_program, diff --git a/cogl/cogl-pipeline-state-private.h b/cogl/cogl-pipeline-state-private.h index d93771bc..ef7665ad 100644 --- a/cogl/cogl-pipeline-state-private.h +++ b/cogl/cogl-pipeline-state-private.h @@ -79,6 +79,10 @@ gboolean _cogl_pipeline_cull_face_state_equal (CoglPipeline *authority0, CoglPipeline *authority1); +gboolean +_cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1); + void _cogl_pipeline_hash_color_state (CoglPipeline *authority, CoglPipelineHashState *state); @@ -131,4 +135,13 @@ void _cogl_pipeline_hash_cull_face_state (CoglPipeline *authority, CoglPipelineHashState *state); +void +_cogl_pipeline_hash_uniforms_state (CoglPipeline *authority, + CoglPipelineHashState *state); + +void +_cogl_pipeline_compare_uniform_differences (unsigned long *differences, + CoglPipeline *pipeline0, + CoglPipeline *pipeline1); + #endif /* __COGL_PIPELINE_STATE_PRIVATE_H */ diff --git a/cogl/cogl-pipeline-state.c b/cogl/cogl-pipeline-state.c index db662f4f..8f7eefa3 100644 --- a/cogl/cogl-pipeline-state.c +++ b/cogl/cogl-pipeline-state.c @@ -34,7 +34,7 @@ #include "cogl-blend-string.h" #include "cogl-util.h" #include "cogl-depth-state-private.h" -#include "cogl-pipeline-private.h" +#include "cogl-pipeline-state-private.h" #include "string.h" @@ -238,6 +238,102 @@ _cogl_pipeline_user_shader_equal (CoglPipeline *authority0, authority1->big_state->user_program); } +typedef struct +{ + const CoglBoxedValue **dst_values; + const CoglBoxedValue *src_values; + int override_count; +} GetUniformsClosure; + +static gboolean +get_uniforms_cb (int uniform_num, void *user_data) +{ + GetUniformsClosure *data = user_data; + + if (data->dst_values[uniform_num] == NULL) + data->dst_values[uniform_num] = data->src_values + data->override_count; + + data->override_count++; + + return TRUE; +} + +static void +_cogl_pipeline_get_all_uniform_values (CoglPipeline *pipeline, + const CoglBoxedValue **values) +{ + GetUniformsClosure data; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + memset (values, 0, + sizeof (const CoglBoxedValue *) * ctx->n_uniform_names); + + data.dst_values = values; + + do + { + const CoglPipelineUniformsState *uniforms_state = + &pipeline->big_state->uniforms_state; + + data.override_count = 0; + data.src_values = uniforms_state->override_values; + + if ((pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS)) + _cogl_bitmask_foreach (&uniforms_state->override_mask, + get_uniforms_cb, + &data); + + pipeline = _cogl_pipeline_get_parent (pipeline); + } + while (pipeline); +} + +gboolean +_cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0, + CoglPipeline *authority1) +{ + unsigned long *differences; + const CoglBoxedValue **values0, **values1; + int n_longs; + int i; + + _COGL_GET_CONTEXT (ctx, FALSE); + + if (authority0 == authority1) + return TRUE; + + values0 = g_alloca (sizeof (const CoglBoxedValue *) * ctx->n_uniform_names); + values1 = g_alloca (sizeof (const CoglBoxedValue *) * ctx->n_uniform_names); + + n_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (ctx->n_uniform_names); + differences = g_alloca (n_longs * sizeof (unsigned long)); + memset (differences, 0, sizeof (unsigned long) * n_longs); + _cogl_pipeline_compare_uniform_differences (differences, + authority0, + authority1); + + _cogl_pipeline_get_all_uniform_values (authority0, values0); + _cogl_pipeline_get_all_uniform_values (authority1, values1); + + COGL_FLAGS_FOREACH_START (differences, n_longs, i) + { + const CoglBoxedValue *value0 = values0[i]; + const CoglBoxedValue *value1 = values1[i]; + + if (value0 == NULL || value0->type == COGL_BOXED_NONE) + { + if (value1 != NULL && value1->type != COGL_BOXED_NONE) + return FALSE; + } + else if (!_cogl_boxed_value_equal (value0, value1)) + return FALSE; + } + COGL_FLAGS_FOREACH_END; + + return TRUE; +} + void cogl_pipeline_get_color (CoglPipeline *pipeline, CoglColor *color) @@ -1304,6 +1400,149 @@ cogl_pipeline_set_point_size (CoglPipeline *pipeline, _cogl_pipeline_point_size_equal); } +static CoglBoxedValue * +_cogl_pipeline_override_uniform (CoglPipeline *pipeline, + int location) +{ + CoglPipelineState state = COGL_PIPELINE_STATE_UNIFORMS; + CoglPipelineUniformsState *uniforms_state; + int override_index; + + _COGL_GET_CONTEXT (ctx, NULL); + + g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL); + g_return_val_if_fail (location >= 0, NULL); + g_return_val_if_fail (location < ctx->n_uniform_names, NULL); + + /* - Flush journal primitives referencing the current state. + * - Make sure the pipeline has no dependants so it may be modified. + * - If the pipeline isn't currently an authority for the state being + * changed, then initialize that state from the current authority. + */ + _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE); + + uniforms_state = &pipeline->big_state->uniforms_state; + + /* Count the number of bits that are set below this location. That + should give us the position where our new value should lie */ + override_index = _cogl_bitmask_popcount_upto (&uniforms_state->override_mask, + location); + + _cogl_bitmask_set (&uniforms_state->changed_mask, location, TRUE); + + /* If this pipeline already has an override for this value then we + can just use it directly */ + if (_cogl_bitmask_get (&uniforms_state->override_mask, location)) + return uniforms_state->override_values + override_index; + + /* We need to create a new override value in the right position + within the array. This is pretty inefficient but the hope is that + it will be much more common to modify an existing uniform rather + than modify a new one so it is more important to optimise the + former case. */ + + if (uniforms_state->override_values == NULL) + { + g_assert (override_index == 0); + uniforms_state->override_values = g_new (CoglBoxedValue, 1); + } + else + { + /* We need to grow the array and copy in the old values */ + CoglBoxedValue *old_values = uniforms_state->override_values; + int old_size = _cogl_bitmask_popcount (&uniforms_state->override_mask); + + uniforms_state->override_values = g_new (CoglBoxedValue, old_size + 1); + + /* Copy in the old values leaving a gap for the new value */ + memcpy (uniforms_state->override_values, + old_values, + sizeof (CoglBoxedValue) * override_index); + memcpy (uniforms_state->override_values, + old_values + override_index + 1, + sizeof (CoglBoxedValue) * (old_size - override_index)); + + g_free (old_values); + } + + _cogl_boxed_value_init (uniforms_state->override_values + override_index); + + _cogl_bitmask_set (&uniforms_state->override_mask, location, TRUE); + + return uniforms_state->override_values + override_index; +} + +void +cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, + int uniform_location, + float value) +{ + CoglBoxedValue *boxed_value; + + boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); + + _cogl_boxed_value_set_1f (boxed_value, value); +} + +void +cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, + int uniform_location, + int value) +{ + CoglBoxedValue *boxed_value; + + boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); + + _cogl_boxed_value_set_1i (boxed_value, value); +} + +void +cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, + int uniform_location, + int n_components, + int count, + const float *value) +{ + CoglBoxedValue *boxed_value; + + boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); + + _cogl_boxed_value_set_float (boxed_value, n_components, count, value); +} + +void +cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, + int uniform_location, + int n_components, + int count, + const int *value) +{ + CoglBoxedValue *boxed_value; + + boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); + + _cogl_boxed_value_set_int (boxed_value, n_components, count, value); +} + +void +cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, + int uniform_location, + int dimensions, + int count, + gboolean transpose, + const float *value) +{ + CoglBoxedValue *boxed_value; + + boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location); + + _cogl_boxed_value_set_matrix (boxed_value, + dimensions, + count, + transpose, + value); +} + void _cogl_pipeline_hash_color_state (CoglPipeline *authority, CoglPipelineHashState *state) @@ -1497,3 +1736,90 @@ _cogl_pipeline_hash_cull_face_state (CoglPipeline *authority, cull_face_state, sizeof (CoglPipelineCullFaceState)); } + +void +_cogl_pipeline_hash_uniforms_state (CoglPipeline *authority, + CoglPipelineHashState *state) +{ + /* This isn't used anywhere yet because the uniform state doesn't + affect program generation. It's quite a hassle to implement so + let's just leave it until something actually needs it */ + g_warn_if_reached (); +} + +void +_cogl_pipeline_compare_uniform_differences (unsigned long *differences, + CoglPipeline *pipeline0, + CoglPipeline *pipeline1) +{ + GSList *head0 = NULL; + GSList *head1 = NULL; + CoglPipeline *node0; + CoglPipeline *node1; + int len0 = 0; + int len1 = 0; + int count; + GSList *common_ancestor0; + GSList *common_ancestor1; + + /* This algorithm is copied from + _cogl_pipeline_compare_differences(). It might be nice to share + the code more */ + + for (node0 = pipeline0; node0; node0 = _cogl_pipeline_get_parent (node0)) + { + GSList *link = alloca (sizeof (GSList)); + link->next = head0; + link->data = node0; + head0 = link; + len0++; + } + for (node1 = pipeline1; node1; node1 = _cogl_pipeline_get_parent (node1)) + { + GSList *link = alloca (sizeof (GSList)); + link->next = head1; + link->data = node1; + head1 = link; + len1++; + } + + /* NB: There's no point looking at the head entries since we know both + * pipelines must have the same default pipeline as their root node. */ + common_ancestor0 = head0; + common_ancestor1 = head1; + head0 = head0->next; + head1 = head1->next; + count = MIN (len0, len1) - 1; + while (count--) + { + if (head0->data != head1->data) + break; + common_ancestor0 = head0; + common_ancestor1 = head1; + head0 = head0->next; + head1 = head1->next; + } + + for (head0 = common_ancestor0->next; head0; head0 = head0->next) + { + node0 = head0->data; + if ((node0->differences & COGL_PIPELINE_STATE_UNIFORMS)) + { + const CoglPipelineUniformsState *uniforms_state = + &node0->big_state->uniforms_state; + _cogl_bitmask_set_flags (&uniforms_state->override_mask, + differences); + } + } + for (head1 = common_ancestor1->next; head1; head1 = head1->next) + { + node1 = head1->data; + if ((node1->differences & COGL_PIPELINE_STATE_UNIFORMS)) + { + const CoglPipelineUniformsState *uniforms_state = + &node1->big_state->uniforms_state; + _cogl_bitmask_set_flags (&uniforms_state->override_mask, + differences); + } + } +} diff --git a/cogl/cogl-pipeline-state.h b/cogl/cogl-pipeline-state.h index 5dfd21a1..cd6a22b7 100644 --- a/cogl/cogl-pipeline-state.h +++ b/cogl/cogl-pipeline-state.h @@ -777,6 +777,166 @@ cogl_pipeline_set_front_face_winding (CoglPipeline *pipeline, CoglWinding cogl_pipeline_get_front_face_winding (CoglPipeline *pipeline); +#define cogl_pipeline_set_uniform_1f \ + cogl_pipeline_set_uniform_1f_EXP +/** + * cogl_pipeline_set_uniform_1f: + * @pipeline: A #CoglPipeline object + * @uniform_location: The uniform's location identifier + * @value: The new value for the uniform + * + * Sets a new value for the uniform at @uniform_location. If this + * pipeline has a user program attached and is later used as a source + * for drawing, the given value will be assigned to the uniform which + * can be accessed from the shader's source. The value for + * @uniform_location should be retrieved from the string name of the + * uniform by calling cogl_pipeline_get_uniform_location(). + * + * This function should be used to set uniforms that are of type + * float. It can also be used to set a single member of a float array + * uniform. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, + int uniform_location, + float value); + +#define cogl_pipeline_set_uniform_1i \ + cogl_pipeline_set_uniform_1i_EXP +/** + * cogl_pipeline_set_uniform_1i: + * @pipeline: A #CoglPipeline object + * @uniform_location: The uniform's location identifier + * @value: The new value for the uniform + * + * Sets a new value for the uniform at @uniform_location. If this + * pipeline has a user program attached and is later used as a source + * for drawing, the given value will be assigned to the uniform which + * can be accessed from the shader's source. The value for + * @uniform_location should be retrieved from the string name of the + * uniform by calling cogl_pipeline_get_uniform_location(). + * + * This function should be used to set uniforms that are of type + * int. It can also be used to set a single member of a int array + * uniform or a sampler uniform. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, + int uniform_location, + int value); + +#define cogl_pipeline_set_uniform_float \ + cogl_pipeline_set_uniform_float_EXP +/** + * cogl_pipeline_set_uniform_float: + * @pipeline: A #CoglPipeline object + * @uniform_location: The uniform's location identifier + * @n_components: The number of components in the corresponding uniform's type + * @count: The number of values to set + * @value: Pointer to the new values to set + * + * Sets new values for the uniform at @uniform_location. If this + * pipeline has a user program attached and is later used as a source + * for drawing, the given values will be assigned to the uniform which + * can be accessed from the shader's source. The value for + * @uniform_location should be retrieved from the string name of the + * uniform by calling cogl_pipeline_get_uniform_location(). + * + * This function can be used to set any floating point type uniform, + * including float arrays and float vectors. For example, to set a + * single vec4 uniform you would use 4 for @n_components and 1 for + * @count. To set an array of 8 float values, you could use 1 for + * @n_components and 8 for @count. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, + int uniform_location, + int n_components, + int count, + const float *value); + +#define cogl_pipeline_set_uniform_int \ + cogl_pipeline_set_uniform_int_EXP +/** + * cogl_pipeline_set_uniform_int: + * @pipeline: A #CoglPipeline object + * @uniform_location: The uniform's location identifier + * @n_components: The number of components in the corresponding uniform's type + * @count: The number of values to set + * @value: Pointer to the new values to set + * + * Sets new values for the uniform at @uniform_location. If this + * pipeline has a user program attached and is later used as a source + * for drawing, the given values will be assigned to the uniform which + * can be accessed from the shader's source. The value for + * @uniform_location should be retrieved from the string name of the + * uniform by calling cogl_pipeline_get_uniform_location(). + * + * This function can be used to set any integer type uniform, + * including int arrays and int vectors. For example, to set a single + * ivec4 uniform you would use 4 for @n_components and 1 for + * @count. To set an array of 8 int values, you could use 1 for + * @n_components and 8 for @count. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, + int uniform_location, + int n_components, + int count, + const int *value); + +#define cogl_pipeline_set_uniform_matrix \ + cogl_pipeline_set_uniform_matrix_EXP +/** + * cogl_pipeline_set_uniform_matrix: + * @pipeline: A #CoglPipeline object + * @uniform_location: The uniform's location identifier + * @dimensions: The size of the matrix + * @count: The number of values to set + * @transpose: Whether to transpose the matrix + * @value: Pointer to the new values to set + * + * Sets new values for the uniform at @uniform_location. If this + * pipeline has a user program attached and is later used as a source + * for drawing, the given values will be assigned to the uniform which + * can be accessed from the shader's source. The value for + * @uniform_location should be retrieved from the string name of the + * uniform by calling cogl_pipeline_get_uniform_location(). + * + * This function can be used to set any matrix type uniform, including + * matrix arrays. For example, to set a single mat4 uniform you would + * use 4 for @dimensions and 1 for @count. To set an array of 8 + * mat3 values, you could use 3 for @dimensions and 8 for @count. + * + * If @transpose is %FALSE then the matrix is expected to be in + * column-major order or if it is %TRUE then the matrix is in + * row-major order. You can pass a #CoglMatrix by calling by passing + * the result of cogl_matrix_get_array() in @value and setting + * @transpose to %FALSE. + * + * Since: 2.0 + * Stability: Unstable + */ +void +cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, + int uniform_location, + int dimensions, + int count, + gboolean transpose, + const float *value); + #endif /* COGL_ENABLE_EXPERIMENTAL_API */ G_END_DECLS diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c index 907f692c..c984219a 100644 --- a/cogl/cogl-pipeline.c +++ b/cogl/cogl-pipeline.c @@ -111,6 +111,7 @@ _cogl_pipeline_init_default_pipeline (void) CoglDepthState *depth_state = &big_state->depth_state; CoglPipelineLogicOpsState *logic_ops_state = &big_state->logic_ops_state; CoglPipelineCullFaceState *cull_face_state = &big_state->cull_face_state; + CoglPipelineUniformsState *uniforms_state = &big_state->uniforms_state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -221,6 +222,10 @@ _cogl_pipeline_init_default_pipeline (void) cull_face_state->mode = COGL_PIPELINE_CULL_FACE_MODE_NONE; cull_face_state->front_winding = COGL_WINDING_COUNTER_CLOCKWISE; + _cogl_bitmask_init (&uniforms_state->override_mask); + _cogl_bitmask_init (&uniforms_state->changed_mask); + uniforms_state->override_values = NULL; + ctx->default_pipeline = _cogl_pipeline_object_new (pipeline); } @@ -458,6 +463,21 @@ _cogl_pipeline_free (CoglPipeline *pipeline) pipeline->big_state->user_program) cogl_handle_unref (pipeline->big_state->user_program); + if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS) + { + CoglPipelineUniformsState *uniforms_state + = &pipeline->big_state->uniforms_state; + int n_overrides = _cogl_bitmask_popcount (&uniforms_state->override_mask); + int i; + + for (i = 0; i < n_overrides; i++) + _cogl_boxed_value_destroy (uniforms_state->override_values + i); + g_free (uniforms_state->override_values); + + _cogl_bitmask_destroy (&uniforms_state->override_mask); + _cogl_bitmask_destroy (&uniforms_state->changed_mask); + } + if (pipeline->differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE) g_slice_free (CoglPipelineBigState, pipeline->big_state); @@ -927,6 +947,32 @@ _cogl_pipeline_copy_differences (CoglPipeline *dest, sizeof (CoglPipelineCullFaceState)); } + if (differences & COGL_PIPELINE_STATE_UNIFORMS) + { + int n_overrides = + _cogl_bitmask_popcount (&src->big_state->uniforms_state.override_mask); + int i; + + big_state->uniforms_state.override_values = + g_malloc (n_overrides * sizeof (CoglBoxedValue)); + + for (i = 0; i < n_overrides; i++) + { + CoglBoxedValue *dst_bv = + big_state->uniforms_state.override_values + i; + const CoglBoxedValue *src_bv = + src->big_state->uniforms_state.override_values + i; + + _cogl_boxed_value_copy (dst_bv, src_bv); + } + + _cogl_bitmask_init (&big_state->uniforms_state.override_mask); + _cogl_bitmask_set_bits (&big_state->uniforms_state.override_mask, + &src->big_state->uniforms_state.override_mask); + + _cogl_bitmask_init (&big_state->uniforms_state.changed_mask); + } + /* XXX: we shouldn't bother doing this in most cases since * _copy_differences is typically used to initialize pipeline state * by copying it from the current authority, so it's not actually @@ -1011,6 +1057,14 @@ _cogl_pipeline_init_multi_property_sparse_state (CoglPipeline *pipeline, sizeof (CoglPipelineCullFaceState)); break; } + case COGL_PIPELINE_STATE_UNIFORMS: + { + CoglPipelineUniformsState *uniforms_state = + &pipeline->big_state->uniforms_state; + _cogl_bitmask_init (&uniforms_state->override_mask); + _cogl_bitmask_init (&uniforms_state->changed_mask); + uniforms_state->override_values = NULL; + } } } @@ -2199,6 +2253,12 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0, _cogl_pipeline_user_shader_equal)) goto done; + if (!simple_property_equal (authorities0, authorities1, + pipelines_difference, + COGL_PIPELINE_STATE_UNIFORMS_INDEX, + _cogl_pipeline_uniforms_state_equal)) + goto done; + if (pipelines_difference & COGL_PIPELINE_STATE_LAYERS) { CoglPipelineStateIndex state_index = COGL_PIPELINE_STATE_LAYERS_INDEX; @@ -2606,9 +2666,11 @@ _cogl_pipeline_init_state_hash_functions (void) _cogl_pipeline_hash_point_size_state; state_hash_functions[COGL_PIPELINE_STATE_LOGIC_OPS_INDEX] = _cogl_pipeline_hash_logic_ops_state; + state_hash_functions[COGL_PIPELINE_STATE_UNIFORMS_INDEX] = + _cogl_pipeline_hash_uniforms_state; /* So we get a big error if we forget to update this code! */ - g_assert (COGL_PIPELINE_STATE_SPARSE_COUNT == 13); + g_assert (COGL_PIPELINE_STATE_SPARSE_COUNT == 14); } unsigned int @@ -2804,3 +2866,35 @@ _cogl_pipeline_get_state_for_fragment_codegen (CoglContext *context) return state; } + +int +cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, + const char *uniform_name) +{ + void *location_ptr; + char *uniform_name_copy; + + _COGL_GET_CONTEXT (ctx, -1); + + /* This API is designed as if the uniform locations are specific to + a pipeline but they are actually unique across a whole + CoglContext. Potentially this could just be + cogl_context_get_uniform_location but it seems to make sense to + keep the API this way so that we can change the internals if need + be. */ + + /* Look for an existing uniform with this name */ + if (g_hash_table_lookup_extended (ctx->uniform_name_hash, + uniform_name, + NULL, + &location_ptr)) + return GPOINTER_TO_INT (location_ptr); + + uniform_name_copy = g_strdup (uniform_name); + g_ptr_array_add (ctx->uniform_names, uniform_name_copy); + g_hash_table_insert (ctx->uniform_name_hash, + uniform_name_copy, + GINT_TO_POINTER (ctx->n_uniform_names)); + + return ctx->n_uniform_names++; +} diff --git a/cogl/cogl-pipeline.h b/cogl/cogl-pipeline.h index d93c6f8e..11b71a00 100644 --- a/cogl/cogl-pipeline.h +++ b/cogl/cogl-pipeline.h @@ -138,6 +138,33 @@ cogl_pipeline_foreach_layer (CoglPipeline *pipeline, CoglPipelineLayerCallback callback, void *user_data); +#define cogl_pipeline_get_uniform_location \ + cogl_pipeline_get_uniform_location_EXP +/** + * cogl_pipeline_get_uniform_location: + * @pipeline: A #CoglPipeline object + * @uniform_name: The name of a uniform + * + * This is used to get an integer representing the uniform with the + * name @uniform_name. The integer can be passed to functions such as + * cogl_pipeline_set_uniform_1f() to set the value of a uniform. + * + * This function will always return a valid integer. Ie, unlike + * OpenGL, it does not return -1 if the uniform is not available in + * this pipeline so it can not be used to test whether uniforms are + * present. It is not necessary to set the program on the pipeline + * before calling this function. + * + * Return value: A integer representing the location of the given uniform. + * + * Since: 2.0 + * Stability: Unstable + */ +int +cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, + const char *uniform_name); + + #endif /* COGL_ENABLE_EXPERIMENTAL_API */ G_END_DECLS diff --git a/cogl/cogl-program.c b/cogl/cogl-program.c index 316b1642..d0fb6f08 100644 --- a/cogl/cogl-program.c +++ b/cogl/cogl-program.c @@ -189,71 +189,34 @@ cogl_program_get_uniform_location (CoglHandle handle, return program->custom_uniforms->len - 1; } -static void -cogl_program_uniform_x (CoglHandle handle, - int uniform_no, - int size, - int count, - CoglBoxedType type, - gsize value_size, - gconstpointer value, - gboolean transpose) +static CoglProgramUniform * +cogl_program_modify_uniform (CoglProgram *program, + int uniform_no) { - CoglProgram *program = handle; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - _COGL_RETURN_IF_FAIL (cogl_is_program (handle)); - _COGL_RETURN_IF_FAIL (program != NULL); - - if (uniform_no >= 0 && uniform_no < program->custom_uniforms->len && - size >= 1 && size <= 4 && count >= 1) - { - CoglProgramUniform *uniform = - &g_array_index (program->custom_uniforms, - CoglProgramUniform, uniform_no); + CoglProgramUniform *uniform; - if (count == 1) - { - if (uniform->value.count > 1) - g_free (uniform->value.v.array); + _COGL_RETURN_VAL_IF_FAIL (cogl_is_program (program), NULL); + _COGL_RETURN_VAL_IF_FAIL (uniform_no >= 0 && + uniform_no < program->custom_uniforms->len, + NULL); - memcpy (uniform->value.v.float_value, value, value_size); - } - else - { - if (uniform->value.count > 1) - { - if (uniform->value.count != count || - uniform->value.size != size || - uniform->value.type != type) - { - g_free (uniform->value.v.array); - uniform->value.v.array = g_malloc (count * value_size); - } - } - else - uniform->value.v.array = g_malloc (count * value_size); - - memcpy (uniform->value.v.array, value, count * value_size); - } + uniform = &g_array_index (program->custom_uniforms, + CoglProgramUniform, uniform_no); + uniform->dirty = TRUE; - uniform->value.type = type; - uniform->value.size = size; - uniform->value.count = count; - uniform->value.transpose = transpose; - uniform->dirty = TRUE; - } + return uniform; } void cogl_program_uniform_1f (int uniform_no, float value) { + CoglProgramUniform *uniform; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_program_uniform_x (ctx->current_program, - uniform_no, 1, 1, COGL_BOXED_FLOAT, - sizeof (float), &value, FALSE); + + uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); + _cogl_boxed_value_set_1f (&uniform->value, value); } void @@ -261,19 +224,22 @@ cogl_program_set_uniform_1f (CoglHandle handle, int uniform_location, float value) { - cogl_program_uniform_x (handle, - uniform_location, 1, 1, COGL_BOXED_FLOAT, - sizeof (float), &value, FALSE); + CoglProgramUniform *uniform; + + uniform = cogl_program_modify_uniform (handle, uniform_location); + _cogl_boxed_value_set_1f (&uniform->value, value); } void cogl_program_uniform_1i (int uniform_no, int value) { + CoglProgramUniform *uniform; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_program_uniform_x (ctx->current_program, - uniform_no, 1, 1, COGL_BOXED_INT, - sizeof (int), &value, FALSE); + + uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); + _cogl_boxed_value_set_1i (&uniform->value, value); } void @@ -281,21 +247,24 @@ cogl_program_set_uniform_1i (CoglHandle handle, int uniform_location, int value) { - cogl_program_uniform_x (handle, - uniform_location, 1, 1, COGL_BOXED_INT, - sizeof (int), &value, FALSE); + CoglProgramUniform *uniform; + + uniform = cogl_program_modify_uniform (handle, uniform_location); + _cogl_boxed_value_set_1i (&uniform->value, value); } void cogl_program_uniform_float (int uniform_no, int size, int count, - const GLfloat *value) + const float *value) { + CoglProgramUniform *uniform; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_program_uniform_x (ctx->current_program, - uniform_no, size, count, COGL_BOXED_FLOAT, - sizeof (float) * size, value, FALSE); + + uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); + _cogl_boxed_value_set_float (&uniform->value, size, count, value); } void @@ -305,22 +274,24 @@ cogl_program_set_uniform_float (CoglHandle handle, int count, const float *value) { - cogl_program_uniform_x (handle, - uniform_location, n_components, count, - COGL_BOXED_FLOAT, - sizeof (float) * n_components, value, FALSE); + CoglProgramUniform *uniform; + + uniform = cogl_program_modify_uniform (handle, uniform_location); + _cogl_boxed_value_set_float (&uniform->value, n_components, count, value); } void cogl_program_uniform_int (int uniform_no, int size, int count, - const GLint *value) + const int *value) { + CoglProgramUniform *uniform; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_program_uniform_x (ctx->current_program, - uniform_no, size, count, COGL_BOXED_INT, - sizeof (int) * size, value, FALSE); + + uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); + _cogl_boxed_value_set_int (&uniform->value, size, count, value); } void @@ -330,10 +301,10 @@ cogl_program_set_uniform_int (CoglHandle handle, int count, const int *value) { - cogl_program_uniform_x (handle, - uniform_location, n_components, count, - COGL_BOXED_INT, - sizeof (int) * n_components, value, FALSE); + CoglProgramUniform *uniform; + + uniform = cogl_program_modify_uniform (handle, uniform_location); + _cogl_boxed_value_set_int (&uniform->value, n_components, count, value); } void @@ -344,14 +315,14 @@ cogl_program_set_uniform_matrix (CoglHandle handle, gboolean transpose, const float *value) { - _COGL_RETURN_IF_FAIL (cogl_is_program (handle)); - - cogl_program_uniform_x (handle, - uniform_location, dimensions, count, - COGL_BOXED_MATRIX, - sizeof (float) * dimensions * dimensions, - value, - transpose); + CoglProgramUniform *uniform; + + uniform = cogl_program_modify_uniform (handle, uniform_location); + _cogl_boxed_value_set_matrix (&uniform->value, + dimensions, + count, + transpose, + value); } void @@ -361,9 +332,12 @@ cogl_program_uniform_matrix (int uniform_no, gboolean transpose, const float *value) { + CoglProgramUniform *uniform; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_program_set_uniform_matrix (ctx->current_program, - uniform_no, size, count, transpose, value); + + uniform = cogl_program_modify_uniform (ctx->current_program, uniform_no); + _cogl_boxed_value_set_matrix (&uniform->value, size, count, transpose, value); } /* ARBfp local parameters can be referenced like: @@ -398,84 +372,6 @@ get_local_param_index (const char *uniform_name) return _index; } -static void -_cogl_program_flush_uniform_glsl (GLint location, - CoglBoxedValue *value) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - switch (value->type) - { - case COGL_BOXED_NONE: - break; - - case COGL_BOXED_INT: - { - int *ptr; - - if (value->count == 1) - ptr = value->v.int_value; - else - ptr = value->v.int_array; - - switch (value->size) - { - case 1: ctx->glUniform1iv (location, value->count, ptr); break; - case 2: ctx->glUniform2iv (location, value->count, ptr); break; - case 3: ctx->glUniform3iv (location, value->count, ptr); break; - case 4: ctx->glUniform4iv (location, value->count, ptr); break; - } - } - break; - - case COGL_BOXED_FLOAT: - { - float *ptr; - - if (value->count == 1) - ptr = value->v.float_value; - else - ptr = value->v.float_array; - - switch (value->size) - { - case 1: ctx->glUniform1fv (location, value->count, ptr); break; - case 2: ctx->glUniform2fv (location, value->count, ptr); break; - case 3: ctx->glUniform3fv (location, value->count, ptr); break; - case 4: ctx->glUniform4fv (location, value->count, ptr); break; - } - } - break; - - case COGL_BOXED_MATRIX: - { - float *ptr; - - if (value->count == 1) - ptr = value->v.matrix; - else - ptr = value->v.float_array; - - switch (value->size) - { - case 2: - ctx->glUniformMatrix2fv (location, value->count, - value->transpose, ptr); - break; - case 3: - ctx->glUniformMatrix3fv (location, value->count, - value->transpose, ptr); - break; - case 4: - ctx->glUniformMatrix4fv (location, value->count, - value->transpose, ptr); - break; - } - } - break; - } -} - #ifdef HAVE_COGL_GL static void @@ -536,8 +432,9 @@ _cogl_program_flush_uniforms (CoglProgram *program, switch (_cogl_program_get_language (program)) { case COGL_SHADER_LANGUAGE_GLSL: - _cogl_program_flush_uniform_glsl (uniform->location, - &uniform->value); + _cogl_boxed_value_set_uniform (ctx, + uniform->location, + &uniform->value); break; case COGL_SHADER_LANGUAGE_ARBFP: diff --git a/cogl/cogl-util.c b/cogl/cogl-util.c index f41a2ad1..487a762c 100644 --- a/cogl/cogl-util.c +++ b/cogl/cogl-util.c @@ -25,18 +25,6 @@ #include "config.h" #endif -#include <glib-object.h> -#include <gobject/gvaluecollector.h> - -#include "cogl.h" - -#include "cogl-fixed.h" -#include "cogl-internal.h" -#include "cogl-pipeline.h" -#include "cogl-offscreen.h" -#include "cogl-shader.h" -#include "cogl-texture.h" -#include "cogl-types.h" #include "cogl-util.h" /* @@ -59,154 +47,6 @@ _cogl_util_next_p2 (int a) return rval; } -/* gtypes */ - -/* - * CoglFixed - */ - -static GTypeInfo _info = { - 0, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - 0, - NULL, - NULL, -}; - -static GTypeFundamentalInfo _finfo = { 0, }; - -static void -cogl_value_init_fixed (GValue *value) -{ - value->data[0].v_int = 0; -} - -static void -cogl_value_copy_fixed (const GValue *src, - GValue *dest) -{ - dest->data[0].v_int = src->data[0].v_int; -} - -static char * -cogl_value_collect_fixed (GValue *value, - unsigned int n_collect_values, - GTypeCValue *collect_values, - unsigned int collect_flags) -{ - value->data[0].v_int = collect_values[0].v_int; - - return NULL; -} - -static char * -cogl_value_lcopy_fixed (const GValue *value, - unsigned int n_collect_values, - GTypeCValue *collect_values, - unsigned int collect_flags) -{ - gint32 *fixed_p = collect_values[0].v_pointer; - - if (!fixed_p) - return g_strdup_printf ("value location for '%s' passed as NULL", - G_VALUE_TYPE_NAME (value)); - - *fixed_p = value->data[0].v_int; - - return NULL; -} - -static void -cogl_value_transform_fixed_int (const GValue *src, - GValue *dest) -{ - dest->data[0].v_int = COGL_FIXED_TO_INT (src->data[0].v_int); -} - -static void -cogl_value_transform_fixed_double (const GValue *src, - GValue *dest) -{ - dest->data[0].v_double = COGL_FIXED_TO_DOUBLE (src->data[0].v_int); -} - -static void -cogl_value_transform_fixed_float (const GValue *src, - GValue *dest) -{ - dest->data[0].v_float = COGL_FIXED_TO_FLOAT (src->data[0].v_int); -} - -static void -cogl_value_transform_int_fixed (const GValue *src, - GValue *dest) -{ - dest->data[0].v_int = COGL_FIXED_FROM_INT (src->data[0].v_int); -} - -static void -cogl_value_transform_double_fixed (const GValue *src, - GValue *dest) -{ - dest->data[0].v_int = COGL_FIXED_FROM_DOUBLE (src->data[0].v_double); -} - -static void -cogl_value_transform_float_fixed (const GValue *src, - GValue *dest) -{ - dest->data[0].v_int = COGL_FIXED_FROM_FLOAT (src->data[0].v_float); -} - - -static const GTypeValueTable _cogl_fixed_value_table = { - cogl_value_init_fixed, - NULL, - cogl_value_copy_fixed, - NULL, - "i", - cogl_value_collect_fixed, - "p", - cogl_value_lcopy_fixed -}; - -GType -cogl_fixed_get_type (void) -{ - static GType _cogl_fixed_type = 0; - - if (G_UNLIKELY (_cogl_fixed_type == 0)) - { - _info.value_table = & _cogl_fixed_value_table; - _cogl_fixed_type = - g_type_register_fundamental (g_type_fundamental_next (), - g_intern_static_string ("CoglFixed"), - &_info, &_finfo, 0); - - g_value_register_transform_func (_cogl_fixed_type, G_TYPE_INT, - cogl_value_transform_fixed_int); - g_value_register_transform_func (G_TYPE_INT, _cogl_fixed_type, - cogl_value_transform_int_fixed); - - g_value_register_transform_func (_cogl_fixed_type, G_TYPE_FLOAT, - cogl_value_transform_fixed_float); - g_value_register_transform_func (G_TYPE_FLOAT, _cogl_fixed_type, - cogl_value_transform_float_fixed); - - g_value_register_transform_func (_cogl_fixed_type, G_TYPE_DOUBLE, - cogl_value_transform_fixed_double); - g_value_register_transform_func (G_TYPE_DOUBLE, _cogl_fixed_type, - cogl_value_transform_double_fixed); - } - - return _cogl_fixed_type; -} - unsigned int _cogl_util_one_at_a_time_mix (unsigned int hash) { @@ -237,3 +77,46 @@ _cogl_util_ffs (int num) return i; } #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 */ + +#ifndef COGL_UTIL_HAVE_BUILTIN_POPCOUNTL + +const unsigned char +_cogl_util_popcount_table[256] = + { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, + 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 + }; + +#endif /* COGL_UTIL_HAVE_BUILTIN_POPCOUNTL */ diff --git a/cogl/cogl-util.h b/cogl/cogl-util.h index 68fd9150..33b36d07 100644 --- a/cogl/cogl-util.h +++ b/cogl/cogl-util.h @@ -100,6 +100,12 @@ _cogl_util_one_at_a_time_hash (unsigned int hash, unsigned int _cogl_util_one_at_a_time_mix (unsigned int hash); +/* These two builtins are available since GCC 3.4 */ +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define COGL_UTIL_HAVE_BUILTIN_FFSL +#define COGL_UTIL_HAVE_BUILTIN_POPCOUNTL +#endif + /* The 'ffs' function is part of C99 so it isn't always available */ #ifdef HAVE_FFS #define _cogl_util_ffs ffs @@ -128,6 +134,43 @@ cogl_modff (float value, float *int_part) #define cogl_modff modff #endif /* _MSC_VER && _M_IX86 */ +/* The 'ffsl' function is non-standard but GCC has a builtin for it + since 3.4 which we can use */ +#ifdef COGL_UTIL_HAVE_BUILTIN_FFSL +#define _cogl_util_ffsl __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 /* COGL_UTIL_HAVE_BUILTIN_FFSL */ + +#ifdef COGL_UTIL_HAVE_BUILTIN_POPCOUNTL +#define _cogl_util_popcountl __builtin_popcountl +#else +extern const unsigned char _cogl_util_popcount_table[256]; + +/* There are many ways of doing popcount but doing a table lookup + seems to be the most robust against different sizes for long. Some + pages seem to claim it's the fastest method anyway. */ +static inline int +_cogl_util_popcountl (unsigned long num) +{ + int i; + int sum = 0; + + /* Let's hope GCC will unroll this loop.. */ + for (i = 0; i < sizeof (num); i++) + sum += _cogl_util_popcount_table[(num >> (i * 8)) & 0xff]; + + return sum; +} + +#endif /* COGL_UTIL_HAVE_BUILTIN_POPCOUNTL */ + #ifdef COGL_HAS_GLIB_SUPPORT #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) diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c index 05e2dac1..0dce4741 100644 --- a/cogl/winsys/cogl-winsys-glx.c +++ b/cogl/winsys/cogl-winsys-glx.c @@ -49,6 +49,7 @@ #include "cogl-onscreen-private.h" #include "cogl-swap-chain-private.h" #include "cogl-xlib-renderer.h" +#include "cogl-util.h" #include <stdlib.h> #include <sys/types.h> @@ -1697,22 +1698,6 @@ should_use_rectangle (CoglContext *context) return context->rectangle_state == COGL_WINSYS_RECTANGLE_STATE_ENABLE; } -/* GCC's population count builtin is available since version 3.4 */ -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -#define POPCOUNTL(n) __builtin_popcountl(n) -#else -/* HAKMEM 169 */ -static int -hakmem_popcountl (unsigned long n) -{ - unsigned long tmp; - - tmp = n - ((n >> 1) & 033333333333) - ((n >> 2) & 011111111111); - return ((tmp + (tmp >> 3)) & 030707070707) % 63; -} -#define POPCOUNTL(n) hakmem_popcountl(n) -#endif - static gboolean try_create_glx_pixmap (CoglContext *context, CoglTexturePixmapX11 *tex_pixmap, @@ -1765,7 +1750,9 @@ try_create_glx_pixmap (CoglContext *context, * number of 1-bits in color masks against the color depth requested * by the client. */ - if (POPCOUNTL(visual->red_mask|visual->green_mask|visual->blue_mask) == depth) + if (_cogl_util_popcountl (visual->red_mask | + visual->green_mask | + visual->blue_mask) == depth) attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT; else attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT; diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt index 0073408e..f2dd72c1 100644 --- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt +++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt @@ -486,6 +486,7 @@ cogl_matrix_multiply cogl_matrix_rotate cogl_matrix_translate cogl_matrix_scale +cogl_matrix_transpose cogl_matrix_get_array cogl_matrix_get_inverse cogl_matrix_transform_point @@ -597,6 +598,13 @@ cogl_pipeline_remove_layer cogl_pipeline_get_n_layers cogl_pipeline_foreach_layer +cogl_pipeline_get_uniform_location +cogl_pipeline_set_uniform_1f +cogl_pipeline_set_uniform_1i +cogl_pipeline_set_uniform_float +cogl_pipeline_set_uniform_int +cogl_pipeline_set_uniform_matrix + <SUBSECTION Private> cogl_blend_string_error_get_type cogl_blend_string_error_quark diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 1bbb50b0..77240494 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -463,6 +463,7 @@ cogl_matrix_multiply cogl_matrix_rotate cogl_matrix_translate cogl_matrix_scale +cogl_matrix_transpose cogl_matrix_init_from_array cogl_matrix_get_array cogl_matrix_get_inverse @@ -9,8 +9,8 @@ msgstr "" "Project-Id-Version: cogl master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=cogl&keywords=I18N+L10N&component=general\n" -"POT-Creation-Date: 2011-11-03 20:31+0000\n" -"PO-Revision-Date: 2011-11-06 13:44+0100\n" +"POT-Creation-Date: 2011-11-15 10:59+0000\n" +"PO-Revision-Date: 2011-11-17 14:16+0100\n" "Last-Translator: Jorge González <jorgegonz@svn.gnome.org>\n" "Language-Team: Español; Castellano <gnome-es-list@gnome.org>\n" "MIME-Version: 1.0\n" @@ -110,23 +110,23 @@ msgstr "Rastrear matrices" #: ../cogl/cogl-debug-options.h:58 msgid "Trace all matrix manipulation" -msgstr "" +msgstr "Rastrear toda la manipulación de matrices" #: ../cogl/cogl-debug-options.h:63 msgid "Trace Misc Drawing" -msgstr "" +msgstr "Rastrear dibujado variado" #: ../cogl/cogl-debug-options.h:64 msgid "Trace some misc drawing operations" -msgstr "" +msgstr "Rastrear algunas operaciones de dibujado variadas" #: ../cogl/cogl-debug-options.h:68 msgid "Trace Pango Renderer" -msgstr "" +msgstr "Rastrear dibujado Pango" #: ../cogl/cogl-debug-options.h:69 msgid "Trace the Cogl Pango renderer" -msgstr "" +msgstr "Rastrear el dibujado Pango de Cogl" #: ../cogl/cogl-debug-options.h:73 msgid "Trace CoglTexturePixmap backend" @@ -177,23 +177,23 @@ msgstr "" #: ../cogl/cogl-debug-options.h:93 msgid "Disable GL Vertex Buffers" -msgstr "" +msgstr "Desactivar los búferes vertex de GL" #: ../cogl/cogl-debug-options.h:94 msgid "Disable use of OpenGL vertex buffer objects" -msgstr "" +msgstr "Desactivar el uso de objetos de búfer vertex de OpenGL" #: ../cogl/cogl-debug-options.h:98 msgid "Disable GL Pixel Buffers" -msgstr "" +msgstr "Desactivar los búferes de píxel GL" #: ../cogl/cogl-debug-options.h:99 msgid "Disable use of OpenGL pixel buffer objects" -msgstr "" +msgstr "Desactivar el uso de objetos de búfer de píxeles de OpenGL" #: ../cogl/cogl-debug-options.h:103 msgid "Disable software rect transform" -msgstr "" +msgstr "Desactivar la transformación de rectas por software" #: ../cogl/cogl-debug-options.h:104 msgid "Use the GPU to transform rectangular geometry" @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: cogl master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=cogl&keywords=I18N+L10N&component=general\n" -"POT-Creation-Date: 2011-09-09 14:07+0000\n" -"PO-Revision-Date: 2011-09-10 19:17+0300\n" +"POT-Creation-Date: 2011-10-14 16:04+0000\n" +"PO-Revision-Date: 2011-11-16 11:01+0200\n" "Last-Translator: Muhammet Kara <muhammet.k@gmail.com>\n" "Language-Team: Turkish <gnome-turk@gnome.org>\n" "MIME-Version: 1.0\n" @@ -19,19 +19,321 @@ msgstr "" "Language: tr\n" "X-Generator: Lokalize 1.2\n" -#: ../cogl/cogl-debug.c:206 +#: ../cogl/cogl-debug.c:154 +msgid "Supported debug values:" +msgstr "Desteklenen hata ayıklama değerleri:" + +#: ../cogl/cogl-debug.c:159 +msgid "Special debug values:" +msgstr "Özel hata ayıklama değerleri:" + +#: ../cogl/cogl-debug.c:161 ../cogl/cogl-debug.c:163 +msgid "Enables all non-behavioural debug options" +msgstr "" + +#: ../cogl/cogl-debug.c:207 msgid "Cogl debugging flags to set" msgstr "Atanacak Cogl hata ayıklama imleri" -#: ../cogl/cogl-debug.c:208 +#: ../cogl/cogl-debug.c:209 msgid "Cogl debugging flags to unset" msgstr "Kaldırılacak Cogl hata ayıklama imleri" -#: ../cogl/cogl-debug.c:257 +#: ../cogl/cogl-debug.c:258 msgid "Cogl Options" msgstr "Cogl Seçenekleri" -#: ../cogl/cogl-debug.c:258 +#: ../cogl/cogl-debug.c:259 msgid "Show Cogl options" msgstr "Cogl seçeneklerini göster" +#: ../cogl/cogl-debug-options.h:25 ../cogl/cogl-debug-options.h:30 +#: ../cogl/cogl-debug-options.h:35 ../cogl/cogl-debug-options.h:40 +#: ../cogl/cogl-debug-options.h:45 ../cogl/cogl-debug-options.h:50 +#: ../cogl/cogl-debug-options.h:55 ../cogl/cogl-debug-options.h:61 +#: ../cogl/cogl-debug-options.h:66 ../cogl/cogl-debug-options.h:71 +#: ../cogl/cogl-debug-options.h:158 ../cogl/cogl-debug-options.h:163 +#: ../cogl/cogl-debug-options.h:168 ../cogl/cogl-debug-options.h:184 +msgid "Cogl Tracing" +msgstr "" + +#: ../cogl/cogl-debug-options.h:27 +msgid "CoglObject references" +msgstr "" + +#: ../cogl/cogl-debug-options.h:28 +msgid "Debug ref counting issues for CoglObjects" +msgstr "" + +#: ../cogl/cogl-debug-options.h:32 +msgid "Trace Texture Slicing" +msgstr "" + +#: ../cogl/cogl-debug-options.h:33 +msgid "debug the creation of texture slices" +msgstr "" + +#: ../cogl/cogl-debug-options.h:37 +msgid "Trace Atlas Textures" +msgstr "" + +#: ../cogl/cogl-debug-options.h:38 +msgid "Debug texture atlas management" +msgstr "" + +#: ../cogl/cogl-debug-options.h:42 +msgid "Trace Blend Strings" +msgstr "" + +#: ../cogl/cogl-debug-options.h:43 +msgid "Debug CoglBlendString parsing" +msgstr "" + +#: ../cogl/cogl-debug-options.h:47 +msgid "Trace Journal" +msgstr "" + +#: ../cogl/cogl-debug-options.h:48 +msgid "View all the geometry passing through the journal" +msgstr "" + +#: ../cogl/cogl-debug-options.h:52 +msgid "Trace Batching" +msgstr "" + +#: ../cogl/cogl-debug-options.h:53 +msgid "Show how geometry is being batched in the journal" +msgstr "" + +#: ../cogl/cogl-debug-options.h:57 +msgid "Trace matrices" +msgstr "" + +#: ../cogl/cogl-debug-options.h:58 +msgid "Trace all matrix manipulation" +msgstr "" + +#: ../cogl/cogl-debug-options.h:63 +msgid "Trace Misc Drawing" +msgstr "" + +#: ../cogl/cogl-debug-options.h:64 +msgid "Trace some misc drawing operations" +msgstr "" + +#: ../cogl/cogl-debug-options.h:68 +msgid "Trace Pango Renderer" +msgstr "" + +#: ../cogl/cogl-debug-options.h:69 +msgid "Trace the Cogl Pango renderer" +msgstr "" + +#: ../cogl/cogl-debug-options.h:73 +msgid "Trace CoglTexturePixmap backend" +msgstr "" + +#: ../cogl/cogl-debug-options.h:74 +msgid "Trace the Cogl texture pixmap backend" +msgstr "" + +#: ../cogl/cogl-debug-options.h:76 ../cogl/cogl-debug-options.h:81 +msgid "Visualize" +msgstr "" + +#: ../cogl/cogl-debug-options.h:78 +msgid "Outline rectangles" +msgstr "" + +#: ../cogl/cogl-debug-options.h:79 +msgid "Add wire outlines for all rectangular geometry" +msgstr "" + +#: ../cogl/cogl-debug-options.h:83 +msgid "Show wireframes" +msgstr "" + +#: ../cogl/cogl-debug-options.h:84 +msgid "Add wire outlines for all geometry" +msgstr "" + +#: ../cogl/cogl-debug-options.h:86 ../cogl/cogl-debug-options.h:91 +#: ../cogl/cogl-debug-options.h:96 ../cogl/cogl-debug-options.h:101 +#: ../cogl/cogl-debug-options.h:111 ../cogl/cogl-debug-options.h:116 +#: ../cogl/cogl-debug-options.h:122 ../cogl/cogl-debug-options.h:127 +#: ../cogl/cogl-debug-options.h:132 ../cogl/cogl-debug-options.h:137 +#: ../cogl/cogl-debug-options.h:142 ../cogl/cogl-debug-options.h:147 +#: ../cogl/cogl-debug-options.h:153 ../cogl/cogl-debug-options.h:173 +#: ../cogl/cogl-debug-options.h:178 +msgid "Root Cause" +msgstr "" + +#: ../cogl/cogl-debug-options.h:88 +msgid "Disable Journal batching" +msgstr "" + +#: ../cogl/cogl-debug-options.h:89 +msgid "Disable batching of geometry in the Cogl Journal." +msgstr "" + +#: ../cogl/cogl-debug-options.h:93 +msgid "Disable GL Vertex Buffers" +msgstr "" + +#: ../cogl/cogl-debug-options.h:94 +msgid "Disable use of OpenGL vertex buffer objects" +msgstr "" + +#: ../cogl/cogl-debug-options.h:98 +msgid "Disable GL Pixel Buffers" +msgstr "" + +#: ../cogl/cogl-debug-options.h:99 +msgid "Disable use of OpenGL pixel buffer objects" +msgstr "" + +#: ../cogl/cogl-debug-options.h:103 +msgid "Disable software rect transform" +msgstr "" + +#: ../cogl/cogl-debug-options.h:104 +msgid "Use the GPU to transform rectangular geometry" +msgstr "" + +#: ../cogl/cogl-debug-options.h:106 +msgid "Cogl Specialist" +msgstr "" + +#: ../cogl/cogl-debug-options.h:108 +msgid "Dump atlas images" +msgstr "" + +#: ../cogl/cogl-debug-options.h:109 +msgid "Dump texture atlas changes to an image file" +msgstr "" + +#: ../cogl/cogl-debug-options.h:113 +msgid "Disable texture atlasing" +msgstr "" + +#: ../cogl/cogl-debug-options.h:114 +msgid "Disable use of texture atlasing" +msgstr "" + +#: ../cogl/cogl-debug-options.h:118 +msgid "Disable sharing the texture atlas between text and images" +msgstr "" + +#: ../cogl/cogl-debug-options.h:119 +msgid "" +"When this is set the glyph cache will always use a separate texture for its " +"atlas. Otherwise it will try to share the atlas with images." +msgstr "" + +#: ../cogl/cogl-debug-options.h:124 +msgid "Disable texturing" +msgstr "" + +#: ../cogl/cogl-debug-options.h:125 +msgid "Disable texturing any primitives" +msgstr "" + +#: ../cogl/cogl-debug-options.h:129 +msgid "Disable arbfp" +msgstr "" + +#: ../cogl/cogl-debug-options.h:130 +msgid "Disable use of ARB fragment programs" +msgstr "" + +#: ../cogl/cogl-debug-options.h:134 +msgid "Disable fixed" +msgstr "" + +#: ../cogl/cogl-debug-options.h:135 +msgid "Disable use of the fixed function pipeline backend" +msgstr "" + +#: ../cogl/cogl-debug-options.h:139 +msgid "Disable GLSL" +msgstr "" + +#: ../cogl/cogl-debug-options.h:140 +msgid "Disable use of GLSL" +msgstr "" + +#: ../cogl/cogl-debug-options.h:144 +msgid "Disable blending" +msgstr "" + +#: ../cogl/cogl-debug-options.h:145 +msgid "Disable use of blending" +msgstr "" + +#: ../cogl/cogl-debug-options.h:149 +msgid "Disable non-power-of-two textures" +msgstr "" + +#: ../cogl/cogl-debug-options.h:150 +msgid "" +"Makes Cogl think that the GL driver doesn't support NPOT textures so that it " +"will create sliced textures or textures with waste instead." +msgstr "" + +#: ../cogl/cogl-debug-options.h:155 +msgid "Disable software clipping" +msgstr "" + +#: ../cogl/cogl-debug-options.h:156 +msgid "Disables Cogl's attempts to clip some rectangles in software." +msgstr "" + +#: ../cogl/cogl-debug-options.h:160 +msgid "Show source" +msgstr "" + +#: ../cogl/cogl-debug-options.h:161 +msgid "Show generated ARBfp/GLSL source code" +msgstr "" + +#: ../cogl/cogl-debug-options.h:165 +msgid "Trace some OpenGL" +msgstr "" + +#: ../cogl/cogl-debug-options.h:166 +msgid "Traces some select OpenGL calls" +msgstr "" + +#: ../cogl/cogl-debug-options.h:170 +msgid "Trace offscreen support" +msgstr "" + +#: ../cogl/cogl-debug-options.h:171 +msgid "Debug offscreen support" +msgstr "" + +#: ../cogl/cogl-debug-options.h:175 +msgid "Disable program caches" +msgstr "" + +#: ../cogl/cogl-debug-options.h:176 +msgid "Disable fallback caches for arbfp and glsl programs" +msgstr "" + +#: ../cogl/cogl-debug-options.h:180 +msgid "Disable read pixel optimization" +msgstr "" + +#: ../cogl/cogl-debug-options.h:181 +msgid "" +"Disable optimization for reading 1px for simple scenes of opaque rectangles" +msgstr "" + +#: ../cogl/cogl-debug-options.h:186 +msgid "Trace clipping" +msgstr "" + +#: ../cogl/cogl-debug-options.h:187 +msgid "Logs information about how Cogl is implementing clipping" +msgstr "" + diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index 6517b02b..57aee3bd 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -34,6 +34,7 @@ unported_test_sources = \ $(NULL) test_sources = \ + test-bitmask.c \ test-blend-strings.c \ test-depth-test.c \ test-color-mask.c \ @@ -41,6 +42,7 @@ test_sources = \ test-just-vertex-shader.c \ test-path.c \ test-pipeline-user-matrix.c \ + test-pipeline-uniforms.c \ test-wrap-modes.c \ test-sub-texture.c \ $(NULL) @@ -108,12 +110,18 @@ clean-wrappers: # a phony rule that will generate symlink scripts for running individual tests BUILT_SOURCES = wrappers -INCLUDES = -I$(top_srcdir) +# The include of the $(buildir)/cogl directory here is to make it so +# that tests that directly include Cogl source code for whitebox +# testing (such as test-bitmask) will still compile +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_builddir)/cogl test_conformance_CPPFLAGS = \ -DCOGL_ENABLE_EXPERIMENTAL_API \ -DCOGL_DISABLE_DEPRECATED \ - -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" + -DTESTS_DATADIR=\""$(top_srcdir)/tests/data"\" \ + -DCLUTTER_COMPILATION test_conformance_CFLAGS = -g3 -O0 $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) test_conformance_LDADD = $(COGL_DEP_LIBS) $(top_builddir)/cogl/libcogl.la diff --git a/tests/conform/test-bitmask.c b/tests/conform/test-bitmask.c new file mode 100644 index 00000000..36369011 --- /dev/null +++ b/tests/conform/test-bitmask.c @@ -0,0 +1,185 @@ +#include <cogl/cogl.h> + +#include <string.h> +#include <stdarg.h> + +#include "test-utils.h" + +/* This is testing CoglBitmask which is an internal data structure + within Cogl. Cogl doesn't export the symbols for this data type so + we just directly include the source instead */ + +#include <cogl/cogl-bitmask.h> +#include <cogl/cogl-bitmask.c> +#include <cogl/cogl-util.c> + +typedef struct +{ + int n_bits; + int *bits; +} CheckData; + +static gboolean +check_bit (int bit_num, void *user_data) +{ + CheckData *data = user_data; + int i; + + for (i = 0; i < data->n_bits; i++) + if (data->bits[i] == bit_num) + { + data->bits[i] = -1; + return TRUE; + } + + g_assert_not_reached (); + + return TRUE; +} + +static void +verify_bits (const CoglBitmask *bitmask, + ...) +{ + CheckData data; + va_list ap, ap_copy; + int i; + + va_start (ap, bitmask); + G_VA_COPY (ap_copy, ap); + + for (data.n_bits = 0; va_arg (ap, int) != -1; data.n_bits++); + + data.bits = alloca (data.n_bits * (sizeof (int))); + + G_VA_COPY (ap, ap_copy); + + for (i = 0; i < data.n_bits; i++) + data.bits[i] = va_arg (ap, int); + + _cogl_bitmask_foreach (bitmask, check_bit, &data); + + for (i = 0; i < data.n_bits; i++) + g_assert_cmpint (data.bits[i], ==, -1); + + g_assert_cmpint (_cogl_bitmask_popcount (bitmask), ==, data.n_bits); + + for (i = 0; i < 1024; i++) + { + int upto_popcount = 0; + int j; + + G_VA_COPY (ap, ap_copy); + + for (j = 0; j < data.n_bits; j++) + if (va_arg (ap, int) < i) + upto_popcount++; + + g_assert_cmpint (_cogl_bitmask_popcount_upto (bitmask, i), + ==, + upto_popcount); + + G_VA_COPY (ap, ap_copy); + + for (j = 0; j < data.n_bits; j++) + if (va_arg (ap, int) == i) + break; + + g_assert_cmpint (_cogl_bitmask_get (bitmask, i), ==, (j < data.n_bits)); + } +} + +void +test_cogl_bitmask (TestUtilsGTestFixture *fixture, + void *data) +{ + CoglBitmask bitmask; + CoglBitmask other_bitmask; + /* A dummy bit to make it use arrays sometimes */ + int dummy_bit; + int i; + + for (dummy_bit = -1; dummy_bit < 256; dummy_bit += 40) + { + _cogl_bitmask_init (&bitmask); + _cogl_bitmask_init (&other_bitmask); + + if (dummy_bit != -1) + _cogl_bitmask_set (&bitmask, dummy_bit, TRUE); + + verify_bits (&bitmask, dummy_bit, -1); + + _cogl_bitmask_set (&bitmask, 1, TRUE); + _cogl_bitmask_set (&bitmask, 4, TRUE); + _cogl_bitmask_set (&bitmask, 5, TRUE); + + verify_bits (&bitmask, 1, 4, 5, dummy_bit, -1); + + _cogl_bitmask_set (&bitmask, 4, FALSE); + + verify_bits (&bitmask, 1, 5, dummy_bit, -1); + + _cogl_bitmask_clear_all (&bitmask); + + verify_bits (&bitmask, -1); + + if (dummy_bit != -1) + _cogl_bitmask_set (&bitmask, dummy_bit, TRUE); + + verify_bits (&bitmask, dummy_bit, -1); + + _cogl_bitmask_set (&bitmask, 1, TRUE); + _cogl_bitmask_set (&bitmask, 4, TRUE); + _cogl_bitmask_set (&bitmask, 5, TRUE); + _cogl_bitmask_set (&other_bitmask, 5, TRUE); + _cogl_bitmask_set (&other_bitmask, 6, TRUE); + + _cogl_bitmask_set_bits (&bitmask, &other_bitmask); + + verify_bits (&bitmask, 1, 4, 5, 6, dummy_bit, -1); + verify_bits (&other_bitmask, 5, 6, -1); + + _cogl_bitmask_set (&bitmask, 6, FALSE); + + verify_bits (&bitmask, 1, 4, 5, dummy_bit, -1); + + _cogl_bitmask_xor_bits (&bitmask, &other_bitmask); + + verify_bits (&bitmask, 1, 4, 6, dummy_bit, -1); + verify_bits (&other_bitmask, 5, 6, -1); + + _cogl_bitmask_set_range (&bitmask, 5, TRUE); + + verify_bits (&bitmask, 0, 1, 2, 3, 4, 6, dummy_bit, -1); + + _cogl_bitmask_set_range (&bitmask, 4, FALSE); + + verify_bits (&bitmask, 4, 6, dummy_bit, -1); + + _cogl_bitmask_destroy (&other_bitmask); + _cogl_bitmask_destroy (&bitmask); + } + + /* Extra tests for really long bitmasks */ + _cogl_bitmask_init (&bitmask); + _cogl_bitmask_set_range (&bitmask, 400, TRUE); + _cogl_bitmask_init (&other_bitmask); + _cogl_bitmask_set (&other_bitmask, 5, TRUE); + _cogl_bitmask_xor_bits (&bitmask, &other_bitmask); + + for (i = 0; i < 1024; i++) + g_assert_cmpint (_cogl_bitmask_get (&bitmask, i), + ==, + (i == 5 ? FALSE : + i < 400 ? TRUE : + FALSE)); + + _cogl_bitmask_set_range (&other_bitmask, 500, TRUE); + _cogl_bitmask_set_bits (&bitmask, &other_bitmask); + + for (i = 0; i < 1024; i++) + g_assert_cmpint (_cogl_bitmask_get (&bitmask, i), ==, (i < 500)); + + if (g_test_verbose ()) + g_print ("OK\n"); +} diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index 6e25c2c4..5be834b6 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -161,6 +161,9 @@ main (int argc, char **argv) UNPORTED_TEST ("/cogl/vertex-array", test_cogl_primitive); ADD_TEST ("/cogl/shaders", test_cogl_just_vertex_shader); + ADD_TEST ("/cogl/shaders", test_cogl_pipeline_uniforms); + + ADD_TEST ("/cogl/internal/bitmask", test_cogl_bitmask); /* left to the end because they aren't currently very orthogonal and tend to * break subsequent tests! */ diff --git a/tests/conform/test-pipeline-uniforms.c b/tests/conform/test-pipeline-uniforms.c new file mode 100644 index 00000000..8908bf72 --- /dev/null +++ b/tests/conform/test-pipeline-uniforms.c @@ -0,0 +1,428 @@ +#include <cogl/cogl.h> + +#include <string.h> + +#include "test-utils.h" + +#define LONG_ARRAY_SIZE 128 + +typedef struct _TestState +{ + CoglPipeline *pipeline_red; + CoglPipeline *pipeline_green; + CoglPipeline *pipeline_blue; + + CoglPipeline *matrix_pipeline; + CoglPipeline *vector_pipeline; + CoglPipeline *int_pipeline; + + CoglPipeline *long_pipeline; + int long_uniform_locations[LONG_ARRAY_SIZE]; +} TestState; + +static const char +color_source[] = + "uniform float red, green, blue;\n" + "\n" + "void\n" + "main ()\n" + "{\n" + " cogl_color_out = vec4 (red, green, blue, 1.0);\n" + "}\n"; + +static const char +matrix_source[] = + "uniform mat4 matrix_array[4];\n" + "\n" + "void\n" + "main ()\n" + "{\n" + " vec4 color = vec4 (0.0, 0.0, 0.0, 1.0);\n" + " int i;\n" + "\n" + " for (i = 0; i < 4; i++)\n" + " color = matrix_array[i] * color;\n" + "\n" + " cogl_color_out = color;\n" + "}\n"; + +static const char +vector_source[] = + "uniform vec4 vector_array[2];\n" + "uniform vec3 short_vector;\n" + "\n" + "void\n" + "main ()\n" + "{\n" + " cogl_color_out = (vector_array[0] +\n" + " vector_array[1] +\n" + " vec4 (short_vector, 1.0));\n" + "}\n"; + +static const char +int_source[] = + "uniform ivec4 vector_array[2];\n" + "uniform int single_value;\n" + "\n" + "void\n" + "main ()\n" + "{\n" + " cogl_color_out = (vec4 (vector_array[0]) +\n" + " vec4 (vector_array[1]) +\n" + " vec4 (float (single_value), 0.0, 0.0, 255.0)) / 255.0;\n" + "}\n"; + +static const char +long_source[] = + "uniform int long_array[" G_STRINGIFY (LONG_ARRAY_SIZE) "];\n" + "const int last_index = " G_STRINGIFY (LONG_ARRAY_SIZE) " - 1;\n" + "\n" + "void\n" + "main ()\n" + "{\n" + " cogl_color_out = vec4 (float (long_array[last_index]), 0.0, 0.0, 1.0);\n" + "}\n"; + +static CoglPipeline * +create_pipeline_for_shader (const char *shader_source) +{ + CoglPipeline *pipeline; + CoglHandle shader; + CoglHandle program; + + pipeline = cogl_pipeline_new (); + + shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT); + cogl_shader_source (shader, shader_source); + + program = cogl_create_program (); + cogl_program_attach_shader (program, shader); + + cogl_pipeline_set_user_program (pipeline, program); + + cogl_handle_unref (shader); + cogl_handle_unref (program); + + return pipeline; +} + +static void +init_state (TestState *state) +{ + int uniform_location; + + state->pipeline_red = create_pipeline_for_shader (color_source); + + uniform_location = + cogl_pipeline_get_uniform_location (state->pipeline_red, "red"); + cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 1.0f); + uniform_location = + cogl_pipeline_get_uniform_location (state->pipeline_red, "green"); + cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 0.0f); + uniform_location = + cogl_pipeline_get_uniform_location (state->pipeline_red, "blue"); + cogl_pipeline_set_uniform_1f (state->pipeline_red, uniform_location, 0.0f); + + state->pipeline_green = cogl_pipeline_copy (state->pipeline_red); + uniform_location = + cogl_pipeline_get_uniform_location (state->pipeline_green, "green"); + cogl_pipeline_set_uniform_1f (state->pipeline_green, uniform_location, 1.0f); + + state->pipeline_blue = cogl_pipeline_copy (state->pipeline_red); + uniform_location = + cogl_pipeline_get_uniform_location (state->pipeline_blue, "blue"); + cogl_pipeline_set_uniform_1f (state->pipeline_blue, uniform_location, 1.0f); + + state->matrix_pipeline = create_pipeline_for_shader (matrix_source); + state->vector_pipeline = create_pipeline_for_shader (vector_source); + state->int_pipeline = create_pipeline_for_shader (int_source); + + state->long_pipeline = NULL; +} + +static void +init_long_pipeline_state (TestState *state) +{ + int i; + + state->long_pipeline = create_pipeline_for_shader (long_source); + + /* This tries to lookup a large number of uniform names to make sure + that the bitmask of overriden uniforms flows over the size of a + single long so that it has to resort to allocating it */ + for (i = 0; i < LONG_ARRAY_SIZE; i++) + { + char *uniform_name = g_strdup_printf ("long_array[%i]", i); + state->long_uniform_locations[i] = + cogl_pipeline_get_uniform_location (state->long_pipeline, + uniform_name); + g_free (uniform_name); + } +} + +static void +destroy_state (TestState *state) +{ + cogl_object_unref (state->pipeline_red); + cogl_object_unref (state->pipeline_green); + cogl_object_unref (state->pipeline_blue); + cogl_object_unref (state->matrix_pipeline); + cogl_object_unref (state->vector_pipeline); + cogl_object_unref (state->int_pipeline); + + if (state->long_pipeline) + cogl_object_unref (state->long_pipeline); +} + +static void +paint_pipeline (CoglPipeline *pipeline, int pos) +{ + cogl_push_source (pipeline); + cogl_rectangle (pos * 10, 0, pos * 10 + 10, 10); + cogl_pop_source (); +} + +static void +paint_color_pipelines (TestState *state) +{ + CoglPipeline *temp_pipeline; + int uniform_location; + int i; + + /* Paint with the first pipeline that sets the uniforms to bright + red */ + paint_pipeline (state->pipeline_red, 0); + + /* Paint with the two other pipelines. These inherit from the red + pipeline and only override one other component. The values for + the two other components should be inherited from the red + pipeline. */ + paint_pipeline (state->pipeline_green, 1); + paint_pipeline (state->pipeline_blue, 2); + + /* Try modifying a single pipeline for multiple rectangles */ + temp_pipeline = cogl_pipeline_copy (state->pipeline_green); + uniform_location = cogl_pipeline_get_uniform_location (temp_pipeline, + "green"); + + for (i = 0; i <= 8; i++) + { + cogl_pipeline_set_uniform_1f (temp_pipeline, uniform_location, + i / 8.0f); + paint_pipeline (temp_pipeline, i + 3); + } + + cogl_object_unref (temp_pipeline); +} + +static void +paint_matrix_pipeline (CoglPipeline *pipeline) +{ + CoglMatrix matrices[4]; + float matrix_floats[16 * 4]; + int uniform_location; + int i; + + for (i = 0; i < 4; i++) + cogl_matrix_init_identity (matrices + i); + + /* Use the first matrix to make the color red */ + cogl_matrix_translate (matrices + 0, 1.0f, 0.0f, 0.0f); + + /* Rotate the vertex so that it ends up green */ + cogl_matrix_rotate (matrices + 1, 90.0f, 0.0f, 0.0f, 1.0f); + + /* Scale the vertex so it ends up halved */ + cogl_matrix_scale (matrices + 2, 0.5f, 0.5f, 0.5f); + + /* Add a blue component in the final matrix. The final matrix is + uploaded as transposed so we need to transpose first to cancel + that out */ + cogl_matrix_translate (matrices + 3, 0.0f, 0.0f, 1.0f); + cogl_matrix_transpose (matrices + 3); + + for (i = 0; i < 4; i++) + memcpy (matrix_floats + i * 16, + cogl_matrix_get_array (matrices + i), + sizeof (float) * 16); + + /* Set the first three matrices as transposed */ + uniform_location = + cogl_pipeline_get_uniform_location (pipeline, "matrix_array"); + cogl_pipeline_set_uniform_matrix (pipeline, + uniform_location, + 4, /* dimensions */ + 3, /* count */ + FALSE, /* not transposed */ + matrix_floats); + + /* Set the last matrix as untransposed */ + uniform_location = + cogl_pipeline_get_uniform_location (pipeline, "matrix_array[3]"); + cogl_pipeline_set_uniform_matrix (pipeline, + uniform_location, + 4, /* dimensions */ + 1, /* count */ + TRUE, /* transposed */ + matrix_floats + 16 * 3); + + paint_pipeline (pipeline, 12); +} + +static void +paint_vector_pipeline (CoglPipeline *pipeline) +{ + float vector_array_values[] = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f }; + float short_vector_values[] = { 0.0f, 0.0f, 1.0f }; + int uniform_location; + + uniform_location = + cogl_pipeline_get_uniform_location (pipeline, "vector_array"); + cogl_pipeline_set_uniform_float (pipeline, + uniform_location, + 4, /* n_components */ + 2, /* count */ + vector_array_values); + + uniform_location = + cogl_pipeline_get_uniform_location (pipeline, "short_vector"); + cogl_pipeline_set_uniform_float (pipeline, + uniform_location, + 3, /* n_components */ + 1, /* count */ + short_vector_values); + + paint_pipeline (pipeline, 13); +} + +static void +paint_int_pipeline (CoglPipeline *pipeline) +{ + int vector_array_values[] = { 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0x00, 0x00 }; + int single_value = 0x80; + int uniform_location; + + uniform_location = + cogl_pipeline_get_uniform_location (pipeline, "vector_array"); + cogl_pipeline_set_uniform_int (pipeline, + uniform_location, + 4, /* n_components */ + 2, /* count */ + vector_array_values); + + uniform_location = + cogl_pipeline_get_uniform_location (pipeline, "single_value"); + cogl_pipeline_set_uniform_1i (pipeline, + uniform_location, + single_value); + + paint_pipeline (pipeline, 14); +} + +static void +paint_long_pipeline (TestState *state) +{ + int i; + + for (i = 0; i < LONG_ARRAY_SIZE; i++) + { + int location = state->long_uniform_locations[i]; + + cogl_pipeline_set_uniform_1i (state->long_pipeline, + location, + i == LONG_ARRAY_SIZE - 1); + } + + paint_pipeline (state->long_pipeline, 15); +} + +static void +paint (TestState *state) +{ + CoglColor color; + + cogl_color_init_from_4ub (&color, 0, 0, 0, 255); + cogl_clear (&color, COGL_BUFFER_BIT_COLOR); + + paint_color_pipelines (state); + paint_matrix_pipeline (state->matrix_pipeline); + paint_vector_pipeline (state->vector_pipeline); + paint_int_pipeline (state->int_pipeline); +} + +static void +check_pos (int pos, guint32 color) +{ + test_utils_check_pixel (pos * 10 + 5, 5, color); +} + +static void +validate_result (void) +{ + int i; + + check_pos (0, 0xff0000ff); + check_pos (1, 0xffff00ff); + check_pos (2, 0xff00ffff); + + for (i = 0; i <= 8; i++) + { + int green_value = i / 8.0f * 255.0f + 0.5f; + check_pos (i + 3, 0xff0000ff + (green_value << 16)); + } + + check_pos (12, 0x0080ffff); + check_pos (13, 0xffffffff); + check_pos (14, 0x80ffffff); +} + +static void +validate_long_pipeline_result (void) +{ + check_pos (15, 0xff0000ff); +} + +void +test_cogl_pipeline_uniforms (TestUtilsGTestFixture *fixture, + void *user_data) +{ + TestUtilsSharedState *shared_state = user_data; + + /* If shaders aren't supported then we can't run the test */ + if (cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) + { + TestState state; + + init_state (&state); + + cogl_ortho (/* left, right */ + 0, cogl_framebuffer_get_width (shared_state->fb), + /* bottom, top */ + cogl_framebuffer_get_height (shared_state->fb), 0, + /* z near, far */ + -1, 100); + + paint (&state); + validate_result (); + + /* Try the test again after querying the location of a large + number of uniforms. This should verify that the bitmasks + still work even if they have to allocate a separate array to + store the bits */ + + init_long_pipeline_state (&state); + paint (&state); + paint_long_pipeline (&state); + validate_result (); + validate_long_pipeline_result (); + + destroy_state (&state); + + if (g_test_verbose ()) + g_print ("OK\n"); + } + else if (g_test_verbose ()) + g_print ("Skipping\n"); +} |