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