mutter/clutter/cogl/common/cogl-handle.h
Robert Bragg c3d9f0bed4 [cogl-handle] Optimize how we define cogl handles
The cogl_is_* functions were showing up quite high on profiles due to
iterating through arrays of cogl handles.

This does away with all the handle arrays and implements a simple struct
inheritance scheme. All cogl objects now add a CoglHandleObject _parent;
member to their main structures. The base object includes 2 members a.t.m; a
ref_count, and a klass pointer. The klass in turn gives you a type and
virtual function for freeing objects of that type.

Each handle type has a _cogl_##handle_type##_get_type () function
automatically defined which returns a GQuark of the handle type, so now
implementing the cogl_is_* funcs is just a case of comparing with
obj->klass->type.

Another outcome of the re-work is that cogl_handle_{ref,unref} are also much
more efficient, and no longer need extending for each handle type added to
cogl. The cogl_##handle_type##_{ref,unref} functions are now deprecated and
are no longer used internally to Clutter or Cogl. Potentially we can remove
them completely before 1.0.
2009-04-02 11:58:43 +01:00

162 lines
6.0 KiB
C

/*
* Clutter COGL
*
* A basic GL/GLES Abstraction/Utility Layer
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2008 OpenedHand
*
* 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __COGL_HANDLE_H
#define __COGL_HANDLE_H
typedef struct _CoglHandleClass
{
GQuark type;
void *virt_free;
} CoglHandleClass;
/* All Cogl objects inherit from this base object by adding a member:
*
* CoglHandleObject _parent;
*
* at the top of its main structure. This structure is initialized
* when you call _cogl_#type_name#_handle_new (new_object);
*/
typedef struct _CoglHandleObject
{
guint ref_count;
CoglHandleClass *klass;
} CoglHandleObject;
/* Helper macro to encapsulate the common code for COGL reference
counted handles */
#if COGL_DEBUG
#define _COGL_HANDLE_DEBUG_NEW(type_name, obj) \
printf ("COGL " G_STRINGIFY (type_name) " NEW %p %i\n", \
(obj), (obj)->ref_count)
#define _COGL_HANDLE_DEBUG_REF(type_name, handle) \
do { \
CoglHandleObject *obj = (CoglHandleObject *)handle; \
printf ("COGL %s REF %p %i\n", \
g_quark_to_string ((obj)->klass->type), \
(obj), (obj)->ref_count) \
} while (0)
#define _COGL_HANDLE_DEBUG_UNREF(type_name, handle) \
do { \
CoglHandleObject *obj = (CoglHandleObject *)handle; \
printf ("COGL %s UNREF %p %i\n", \
g_quark_to_string ((obj)->klass->type), \
(obj), (obj)->ref_count - 1)
} while (0)
#define COGL_HANDLE_DEBUG_FREE(obj) \
printf ("COGL %s FREE %p\n", \
g_quark_to_string ((obj)->klass->type), (obj)) \
#else /* COGL_DEBUG */
#define _COGL_HANDLE_DEBUG_NEW(type_name, obj)
#define _COGL_HANDLE_DEBUG_REF(type_name, obj)
#define _COGL_HANDLE_DEBUG_UNREF(type_name, obj)
#define COGL_HANDLE_DEBUG_FREE(obj)
#endif /* COGL_DEBUG */
#define COGL_HANDLE_DEFINE(TypeName, type_name) \
\
static CoglHandleClass _cogl_##type_name##_class; \
\
static GQuark \
_cogl_##type_name##_get_type (void) \
{ \
static GQuark type = 0; \
if (!type) \
type = g_quark_from_static_string ("Cogl"#TypeName); \
return type; \
} \
\
static CoglHandle \
_cogl_##type_name##_handle_new (Cogl##TypeName *new_obj) \
{ \
CoglHandleObject *obj = &new_obj->_parent; \
obj->ref_count = 1; \
\
obj->klass = &_cogl_##type_name##_class; \
if (!obj->klass->type) \
{ \
obj->klass->type = \
_cogl_##type_name##_get_type (); \
obj->klass->virt_free = _cogl_##type_name##_free; \
} \
\
_COGL_HANDLE_DEBUG_NEW (TypeName, obj); \
return (CoglHandle) new_obj; \
} \
\
Cogl##TypeName * \
_cogl_##type_name##_pointer_from_handle (CoglHandle handle) \
{ \
return (Cogl##TypeName *) handle; \
} \
\
gboolean \
cogl_is_##type_name (CoglHandle handle) \
{ \
CoglHandleObject *obj = (CoglHandleObject *)handle; \
\
return (obj->klass->type == \
_cogl_##type_name##_get_type ()); \
} \
\
CoglHandle G_GNUC_DEPRECATED \
cogl_##type_name##_ref (CoglHandle handle) \
{ \
if (!cogl_is_##type_name (handle)) \
return COGL_INVALID_HANDLE; \
\
_COGL_HANDLE_DEBUG_REF (TypeName, handle); \
\
cogl_handle_ref (handle); \
\
return handle; \
} \
\
void G_GNUC_DEPRECATED \
cogl_##type_name##_unref (CoglHandle handle) \
{ \
if (!cogl_is_##type_name (handle)) \
{ \
g_warning (G_STRINGIFY (cogl_##type_name##_unref) \
": Ignoring unref of Cogl handle " \
"due to type missmatch"); \
return; \
} \
\
_COGL_HANDLE_DEBUG_UNREF (TypeName, handle); \
\
cogl_handle_unref (handle); \
}
#endif /* __COGL_HANDLE_H */