diff --git a/cogl/cogl-debug.c b/cogl/cogl-debug.c index 5b3ecc82b..46ab5b4df 100644 --- a/cogl/cogl-debug.c +++ b/cogl/cogl-debug.c @@ -84,6 +84,7 @@ static const int n_cogl_behavioural_debug_keys = G_N_ELEMENTS (cogl_behavioural_debug_keys); unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS]; +GHashTable *_cogl_debug_instances; static void _cogl_parse_debug_string_for_keys (const char *value, diff --git a/cogl/cogl-debug.h b/cogl/cogl-debug.h index 294de8463..292de2599 100644 --- a/cogl/cogl-debug.h +++ b/cogl/cogl-debug.h @@ -75,6 +75,7 @@ typedef enum { #define COGL_DEBUG_N_INTS COGL_FLAGS_N_INTS_FOR_SIZE (COGL_DEBUG_N_FLAGS) extern unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS]; +extern GHashTable *_cogl_debug_instances; #define COGL_DEBUG_ENABLED(flag) \ COGL_FLAGS_GET (_cogl_debug_flags, flag) diff --git a/cogl/cogl-object-private.h b/cogl/cogl-object-private.h index e8b4ed013..e4c450e46 100644 --- a/cogl/cogl-object-private.h +++ b/cogl/cogl-object-private.h @@ -123,51 +123,84 @@ struct _CoglObject #define _COGL_HANDLE_DEBUG_UNREF _COGL_OBJECT_DEBUG_UNREF #define COGL_HANDLE_DEBUG_FREE COGL_OBJECT_DEBUG_FREE -#define COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ - \ -static CoglObjectClass _cogl_##type_name##_class; \ - \ -GQuark \ -_cogl_object_##type_name##_get_type (void) \ -{ \ - static GQuark type = 0; \ - if (!type) \ - { \ - type = g_quark_from_static_string ("Cogl"#TypeName); \ - { code; } \ - } \ - return type; \ -} \ - \ -GQuark \ -_cogl_handle_##type_name##_get_type (void) \ -{ \ - return _cogl_object_##type_name##_get_type (); \ -} \ - \ -static Cogl##TypeName * \ -_cogl_##type_name##_object_new (Cogl##TypeName *new_obj) \ -{ \ - CoglObject *obj = (CoglObject *)&new_obj->_parent; \ - obj->ref_count = 1; \ - obj->n_user_data_entries = 0; \ - obj->user_data_array = NULL; \ - \ - obj->klass = &_cogl_##type_name##_class; \ - if (!obj->klass->type) \ - { \ - obj->klass->type = _cogl_object_##type_name##_get_type ();\ - obj->klass->virt_free = _cogl_##type_name##_free; \ - } \ - \ - _COGL_OBJECT_DEBUG_NEW (TypeName, obj); \ - return new_obj; \ -} \ - \ -Cogl##TypeName * \ -_cogl_##type_name##_pointer_from_handle (CoglHandle handle) \ -{ \ - return handle; \ +#define COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ + \ +static CoglObjectClass _cogl_##type_name##_class; \ +static unsigned long _cogl_object_##type_name##_count; \ + \ +static inline void \ +_cogl_object_##type_name##_inc (void) \ +{ \ + _cogl_object_##type_name##_count++; \ +} \ + \ +static inline void \ +_cogl_object_##type_name##_dec (void) \ +{ \ + _cogl_object_##type_name##_count--; \ +} \ + \ +static void \ +_cogl_object_##type_name##_indirect_free (CoglObject *obj) \ +{ \ + _cogl_##type_name##_free ((Cogl##TypeName *) obj); \ + _cogl_object_##type_name##_dec (); \ +} \ + \ +GQuark \ +_cogl_object_##type_name##_get_type (void) \ +{ \ + static GQuark type = 0; \ + if (!type) \ + { \ + type = g_quark_from_static_string ("Cogl"#TypeName); \ + _cogl_object_##type_name##_count = 0; \ + \ + if (_cogl_debug_instances == NULL) \ + _cogl_debug_instances = \ + g_hash_table_new (g_str_hash, g_str_equal); \ + \ + g_hash_table_insert (_cogl_debug_instances, \ + "Cogl"#TypeName, \ + &_cogl_object_##type_name##_count); \ + \ + { code; } \ + } \ + return type; \ +} \ + \ +GQuark \ +_cogl_handle_##type_name##_get_type (void) \ +{ \ + return _cogl_object_##type_name##_get_type (); \ +} \ + \ +static Cogl##TypeName * \ +_cogl_##type_name##_object_new (Cogl##TypeName *new_obj) \ +{ \ + CoglObject *obj = (CoglObject *)&new_obj->_parent; \ + obj->ref_count = 0; \ + cogl_object_ref (obj); \ + obj->n_user_data_entries = 0; \ + obj->user_data_array = NULL; \ + \ + obj->klass = &_cogl_##type_name##_class; \ + if (!obj->klass->type) \ + { \ + obj->klass->type = _cogl_object_##type_name##_get_type (); \ + obj->klass->virt_free = \ + _cogl_object_##type_name##_indirect_free; \ + } \ + \ + _cogl_object_##type_name##_inc (); \ + _COGL_OBJECT_DEBUG_NEW (TypeName, obj); \ + return new_obj; \ +} \ + \ +Cogl##TypeName * \ +_cogl_##type_name##_pointer_from_handle (CoglHandle handle) \ +{ \ + return handle; \ } #define COGL_OBJECT_DEFINE_WITH_CODE(TypeName, type_name, code) \ diff --git a/cogl/cogl-object.c b/cogl/cogl-object.c index 90109eba2..418005690 100644 --- a/cogl/cogl-object.c +++ b/cogl/cogl-object.c @@ -247,3 +247,35 @@ cogl_object_get_user_data (CoglObject *object, CoglUserDataKey *key) return NULL; } +void +cogl_debug_object_foreach_type (CoglDebugObjectForeachTypeCallback func, + void *user_data) +{ + GHashTableIter iter; + unsigned long *instance_count; + CoglDebugObjectTypeInfo info; + + g_hash_table_iter_init (&iter, _cogl_debug_instances); + while (g_hash_table_iter_next (&iter, + (void *) &info.name, + (void *) &instance_count)) + { + info.instance_count = *instance_count; + func (&info, user_data); + } +} + +static void +print_instances_cb (const CoglDebugObjectTypeInfo *info, + void *user_data) +{ + g_print ("\t%s: %lu\n", info->name, info->instance_count); +} + +void +cogl_debug_object_print_instances (void) +{ + g_print ("Cogl instances:\n"); + + cogl_debug_object_foreach_type (print_instances_cb, NULL); +} diff --git a/cogl/cogl-object.h b/cogl/cogl-object.h index 71dd8bd7c..f948c7f0d 100644 --- a/cogl/cogl-object.h +++ b/cogl/cogl-object.h @@ -81,6 +81,37 @@ typedef struct */ typedef void (*CoglUserDataDestroyCallback) (void *user_data); +/** + * CoglDebugObjectTypeInfo: + * @name: A human readable name for the type. + * @instance_count: The number of objects of this type that are + * currently in use + * + * This struct is used to pass information to the callback when + * cogl_debug_object_foreach_type() is called. + * + * Since: 1.8 + * Stability: unstable + */ +typedef struct +{ + const char *name; + unsigned long instance_count; +} CoglDebugObjectTypeInfo; + +/** + * CoglDebugObjectForeachTypeCallback: + * @info: A pointer to a struct containing information about the type. + * + * A callback function to use for cogl_debug_object_foreach_type(). + * + * Since: 1.8 + * Stability: unstable + */ +typedef void +(* CoglDebugObjectForeachTypeCallback) (const CoglDebugObjectTypeInfo *info, + void *user_data); + /** * cogl_object_set_user_data: (skip) * @object: The object to associate private data with @@ -123,5 +154,47 @@ cogl_object_set_user_data (CoglObject *object, void * cogl_object_get_user_data (CoglObject *object, CoglUserDataKey *key); + +#ifdef COGL_ENABLE_EXPERIMENTAL_API + +#define cogl_debug_object_foreach_type \ + cogl_debug_object_foreach_type_EXP + +/** + * cogl_debug_object_foreach_type: + * func: A callback function for each type + * user_data: A pointer to pass to @func + * + * Invokes @func once for each type of object that Cogl uses and + * passes a count of the number of objects for that type. This is + * intended to be used solely for debugging purposes to track down + * issues with objects leaking. + * + * Since: 1.8 + * Stability: unstable + */ +void +cogl_debug_object_foreach_type (CoglDebugObjectForeachTypeCallback func, + void *user_data); + +#define cogl_debug_object_print_instances \ + cogl_debug_object_print_instances_EXP + +/** + * cogl_debug_object_print_instances: + * + * Prints a list of all the object types that Cogl uses along with the + * number of objects of that type that are currently in use. This is + * intended to be used solely for debugging purposes to track down + * issues with objects leaking. + * + * Since: 1.8 + * Stability: unstable + */ +void +cogl_debug_object_print_instances (void); + +#endif /* COGL_ENABLE_EXPERIMENTAL_API */ + #endif /* __COGL_OBJECT_H */