1 /* 2 * Cogl 3 * 4 * A Low Level GPU Graphics and Utilities API 5 * 6 * Copyright (C) 2008,2009,2010 Intel Corporation. 7 * 8 * Permission is hereby granted, free of charge, to any person 9 * obtaining a copy of this software and associated documentation 10 * files (the "Software"), to deal in the Software without 11 * restriction, including without limitation the rights to use, copy, 12 * modify, merge, publish, distribute, sublicense, and/or sell copies 13 * of the Software, and to permit persons to whom the Software is 14 * furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be 17 * included in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 * SOFTWARE. 27 * 28 * Authors: 29 * Robert Bragg <robert@linux.intel.com> 30 */ 31 32 #ifndef __COGL_OBJECT_PRIVATE_H 33 #define __COGL_OBJECT_PRIVATE_H 34 35 #include <glib.h> 36 37 #include "cogl-types.h" 38 #include "cogl-object.h" 39 #include "cogl-debug.h" 40 41 /* For compatability until all components have been converted */ 42 typedef struct _CoglObjectClass CoglHandleClass; 43 typedef struct _CoglObject CoglHandleObject; 44 45 /* XXX: sadly we didn't fully consider when we copied the cairo API 46 * for _set_user_data that the callback doesn't get a pointer to the 47 * instance which is desired in most cases. This means you tend to end 48 * up creating micro allocations for the private data just so you can 49 * pair up the data of interest with the original instance for 50 * identification when it is later destroyed. 51 * 52 * Internally we use a small hack to avoid needing these micro 53 * allocations by actually passing the instance as a second argument 54 * to the callback */ 55 typedef void (*CoglUserDataDestroyInternalCallback) (void *user_data, 56 void *instance); 57 58 typedef struct _CoglObjectClass 59 { 60 #ifdef COGL_HAS_GTYPE_SUPPORT 61 GTypeClass base_class; 62 #endif 63 const char *name; 64 void *virt_free; 65 void *virt_unref; 66 } CoglObjectClass; 67 68 #define COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES 2 69 70 typedef struct 71 { 72 CoglUserDataKey *key; 73 void *user_data; 74 CoglUserDataDestroyInternalCallback destroy; 75 } CoglUserDataEntry; 76 77 /* All Cogl objects inherit from this base object by adding a member: 78 * 79 * CoglObject _parent; 80 * 81 * at the top of its main structure. This structure is initialized 82 * when you call _cogl_#type_name#_object_new (new_object); 83 */ 84 struct _CoglObject 85 { 86 CoglObjectClass *klass; /* equivalent to GTypeInstance */ 87 88 CoglUserDataEntry user_data_entry[ 89 COGL_OBJECT_N_PRE_ALLOCATED_USER_DATA_ENTRIES]; 90 GArray *user_data_array; 91 int n_user_data_entries; 92 93 unsigned int ref_count; 94 }; 95 96 /* Helper macro to encapsulate the common code for COGL reference 97 counted objects */ 98 99 #ifdef COGL_OBJECT_DEBUG 100 101 #define _COGL_OBJECT_DEBUG_NEW(type_name, obj) \ 102 COGL_NOTE (OBJECT, "COGL " G_STRINGIFY (type_name) " NEW %p %i", \ 103 (obj), (obj)->ref_count) 104 105 #define _COGL_OBJECT_DEBUG_REF(type_name, object) G_STMT_START { \ 106 CoglObject *__obj = (CoglObject *)object; \ 107 COGL_NOTE (OBJECT, "COGL %s REF %p %i", \ 108 (__obj)->klass->name, \ 109 (__obj), (__obj)->ref_count); } G_STMT_END 110 111 #define _COGL_OBJECT_DEBUG_UNREF(type_name, object) G_STMT_START { \ 112 CoglObject *__obj = (CoglObject *)object; \ 113 COGL_NOTE (OBJECT, "COGL %s UNREF %p %i", \ 114 (__obj)->klass->name, \ 115 (__obj), (__obj)->ref_count - 1); } G_STMT_END 116 117 #define COGL_OBJECT_DEBUG_FREE(obj) \ 118 COGL_NOTE (OBJECT, "COGL %s FREE %p", \ 119 (obj)->klass->name, (obj)) 120 121 #else /* !COGL_OBJECT_DEBUG */ 122 123 #define _COGL_OBJECT_DEBUG_NEW(type_name, obj) 124 #define _COGL_OBJECT_DEBUG_REF(type_name, obj) 125 #define _COGL_OBJECT_DEBUG_UNREF(type_name, obj) 126 #define COGL_OBJECT_DEBUG_FREE(obj) 127 128 #endif /* COGL_OBJECT_DEBUG */ 129 130 #ifdef COGL_HAS_GTYPE_SUPPORT 131 #define _COGL_GTYPE_INIT_CLASS(type_name) do { \ 132 _cogl_##type_name##_class.base_class.g_type = cogl_##type_name##_get_gtype (); \ 133 } while (0) 134 #else 135 #define _COGL_GTYPE_INIT_CLASS(type_name) 136 #endif 137 138 #define COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ 139 \ 140 CoglObjectClass _cogl_##type_name##_class; \ 141 static unsigned long _cogl_object_##type_name##_count; \ 142 \ 143 static inline void \ 144 _cogl_object_##type_name##_inc (void) \ 145 { \ 146 _cogl_object_##type_name##_count++; \ 147 } \ 148 \ 149 static inline void \ 150 _cogl_object_##type_name##_dec (void) \ 151 { \ 152 _cogl_object_##type_name##_count--; \ 153 } \ 154 \ 155 static void \ 156 _cogl_object_##type_name##_indirect_free (CoglObject *obj) \ 157 { \ 158 _cogl_##type_name##_free ((Cogl##TypeName *) obj); \ 159 _cogl_object_##type_name##_dec (); \ 160 } \ 161 \ 162 static void \ 163 _cogl_object_##type_name##_class_init (void) \ 164 { \ 165 _cogl_object_##type_name##_count = 0; \ 166 \ 167 if (_cogl_debug_instances == NULL) \ 168 _cogl_debug_instances = \ 169 g_hash_table_new (g_str_hash, g_str_equal); \ 170 \ 171 _cogl_##type_name##_class.virt_free = \ 172 _cogl_object_##type_name##_indirect_free; \ 173 _cogl_##type_name##_class.virt_unref = \ 174 _cogl_object_default_unref; \ 175 _cogl_##type_name##_class.name = "Cogl"#TypeName; \ 176 \ 177 g_hash_table_insert (_cogl_debug_instances, \ 178 (void *) _cogl_##type_name##_class.name, \ 179 &_cogl_object_##type_name##_count); \ 180 \ 181 { code; } \ 182 } \ 183 \ 184 static Cogl##TypeName * \ 185 _cogl_##type_name##_object_new (Cogl##TypeName *new_obj) \ 186 { \ 187 CoglObject *obj = (CoglObject *)&new_obj->_parent; \ 188 obj->ref_count = 0; \ 189 cogl_object_ref (obj); \ 190 obj->n_user_data_entries = 0; \ 191 obj->user_data_array = NULL; \ 192 \ 193 obj->klass = &_cogl_##type_name##_class; \ 194 if (!obj->klass->virt_free) \ 195 { \ 196 _cogl_object_##type_name##_class_init (); \ 197 } \ 198 \ 199 _cogl_object_##type_name##_inc (); \ 200 _COGL_OBJECT_DEBUG_NEW (TypeName, obj); \ 201 return new_obj; \ 202 } 203 204 #define COGL_OBJECT_DEFINE_WITH_CODE_GTYPE(TypeName, type_name, code) \ 205 \ 206 COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, \ 207 type_name, \ 208 do { code; } while (0); \ 209 _COGL_GTYPE_INIT_CLASS (type_name)) \ 210 \ 211 CoglBool \ 212 cogl_is_##type_name (void *object) \ 213 { \ 214 CoglObject *obj = object; \ 215 \ 216 if (object == NULL) \ 217 return FALSE; \ 218 \ 219 return obj->klass == &_cogl_##type_name##_class; \ 220 } 221 222 #define COGL_OBJECT_DEFINE_WITH_CODE(TypeName, type_name, code) \ 223 \ 224 COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ 225 \ 226 CoglBool \ 227 cogl_is_##type_name (void *object) \ 228 { \ 229 CoglObject *obj = object; \ 230 \ 231 if (object == NULL) \ 232 return FALSE; \ 233 \ 234 return obj->klass == &_cogl_##type_name##_class; \ 235 } 236 237 #define COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE(TypeName, type_name, code) \ 238 \ 239 COGL_OBJECT_COMMON_DEFINE_WITH_CODE(TypeName, type_name, code) \ 240 \ 241 CoglBool \ 242 _cogl_is_##type_name (void *object) \ 243 { \ 244 CoglObject *obj = object; \ 245 \ 246 if (object == NULL) \ 247 return FALSE; \ 248 \ 249 return obj->klass == &_cogl_##type_name##_class; \ 250 } 251 252 #define COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING(type_name) \ 253 \ 254 void * G_GNUC_DEPRECATED \ 255 cogl_##type_name##_ref (void *object) \ 256 { \ 257 if (!cogl_is_##type_name (object)) \ 258 return NULL; \ 259 \ 260 _COGL_OBJECT_DEBUG_REF (TypeName, object); \ 261 \ 262 cogl_handle_ref (object); \ 263 \ 264 return object; \ 265 } \ 266 \ 267 void G_GNUC_DEPRECATED \ 268 cogl_##type_name##_unref (void *object) \ 269 { \ 270 if (!cogl_is_##type_name (object)) \ 271 { \ 272 g_warning (G_STRINGIFY (cogl_##type_name##_unref) \ 273 ": Ignoring unref of Cogl handle " \ 274 "due to type mismatch"); \ 275 return; \ 276 } \ 277 \ 278 _COGL_OBJECT_DEBUG_UNREF (TypeName, object); \ 279 \ 280 cogl_handle_unref (object); \ 281 } 282 283 #define COGL_OBJECT_DEFINE(TypeName, type_name) \ 284 COGL_OBJECT_DEFINE_WITH_CODE_GTYPE (TypeName, type_name, (void) 0) 285 286 #define COGL_OBJECT_INTERNAL_DEFINE(TypeName, type_name) \ 287 COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE (TypeName, type_name, (void) 0) 288 289 /* For temporary compatability */ 290 #define COGL_HANDLE_INTERNAL_DEFINE_WITH_CODE(TypeName, type_name, code) \ 291 \ 292 COGL_OBJECT_INTERNAL_DEFINE_WITH_CODE (TypeName, type_name, code) \ 293 \ 294 static Cogl##TypeName * \ 295 _cogl_##type_name##_handle_new (CoglHandle handle) \ 296 { \ 297 return _cogl_##type_name##_object_new (handle); \ 298 } 299 300 #define COGL_HANDLE_DEFINE_WITH_CODE(TypeName, type_name, code) \ 301 \ 302 COGL_OBJECT_DEFINE_WITH_CODE (TypeName, type_name, code) \ 303 \ 304 static Cogl##TypeName * \ 305 _cogl_##type_name##_handle_new (CoglHandle handle) \ 306 { \ 307 return _cogl_##type_name##_object_new (handle); \ 308 } 309 310 #define COGL_HANDLE_DEFINE(TypeName, type_name) \ 311 COGL_HANDLE_DEFINE_WITH_CODE (TypeName, type_name, (void) 0) 312 313 void 314 _cogl_object_set_user_data (CoglObject *object, 315 CoglUserDataKey *key, 316 void *user_data, 317 CoglUserDataDestroyInternalCallback destroy); 318 319 void 320 _cogl_object_default_unref (void *obj); 321 322 #endif /* __COGL_OBJECT_PRIVATE_H */ 323 324