summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChun-wei Fan <fanchunwei@src.gnome.org>2011-11-18 12:23:25 +0800
committerChun-wei Fan <fanchunwei@src.gnome.org>2011-11-18 12:23:25 +0800
commitfc99756416f3231b3443871382ec972672d17375 (patch)
tree5e33a77badf1c426bd8203bee108ebf09790024e
parentf5413e456456151b5d9cc9e80c8733675f8b7779 (diff)
parent3e56883c98584034f249b8eb938e65a129ccf8c4 (diff)
downloadcogl-fc99756416f3231b3443871382ec972672d17375.tar.gz
Merge branch 'master' into msvc-support
Conflicts: cogl/cogl-debug.h cogl/cogl-util.h
-rw-r--r--cogl-pango/Makefile.am1
-rw-r--r--cogl/Makefile.am2
-rw-r--r--cogl/cogl-attribute.c6
-rw-r--r--cogl/cogl-bitmask.c164
-rw-r--r--cogl/cogl-bitmask.h120
-rw-r--r--cogl/cogl-boxed-value.c336
-rw-r--r--cogl/cogl-boxed-value.h111
-rw-r--r--cogl/cogl-context-private.h18
-rw-r--r--cogl/cogl-context.c9
-rw-r--r--cogl/cogl-debug.c68
-rw-r--r--cogl/cogl-debug.h4
-rw-r--r--cogl/cogl-fixed.c147
-rw-r--r--cogl/cogl-flags.h65
-rw-r--r--cogl/cogl-internal.h23
-rw-r--r--cogl/cogl-matrix.c17
-rw-r--r--cogl/cogl-matrix.h12
-rw-r--r--cogl/cogl-pipeline-private.h25
-rw-r--r--cogl/cogl-pipeline-progend-glsl.c180
-rw-r--r--cogl/cogl-pipeline-state-private.h13
-rw-r--r--cogl/cogl-pipeline-state.c328
-rw-r--r--cogl/cogl-pipeline-state.h160
-rw-r--r--cogl/cogl-pipeline.c96
-rw-r--r--cogl/cogl-pipeline.h27
-rw-r--r--cogl/cogl-program.c235
-rw-r--r--cogl/cogl-util.c203
-rw-r--r--cogl/cogl-util.h43
-rw-r--r--cogl/winsys/cogl-winsys-glx.c21
-rw-r--r--doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt8
-rw-r--r--doc/reference/cogl/cogl-sections.txt1
-rw-r--r--po/es.po24
-rw-r--r--po/tr.po314
-rw-r--r--tests/conform/Makefile.am12
-rw-r--r--tests/conform/test-bitmask.c185
-rw-r--r--tests/conform/test-conform-main.c3
-rw-r--r--tests/conform/test-pipeline-uniforms.c428
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
diff --git a/po/es.po b/po/es.po
index 005fe0bf..135423f0 100644
--- a/po/es.po
+++ b/po/es.po
@@ -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"
diff --git a/po/tr.po b/po/tr.po
index 64096cca..8a795e18 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -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");
+}