mutter/cogl/cogl-debug.c

286 lines
9.4 KiB
C
Raw Normal View History

/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2009 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 <stdlib.h>
#include <glib/gi18n-lib.h>
#include "cogl.h"
#include "cogl-private.h"
#include "cogl-debug.h"
/* XXX: If you add a debug option, please also add an option
* definition to cogl-debug-options.h. This will enable us - for
* example - to emit a "help" description for the option.
*/
/* NB: Only these options get enabled if COGL_DEBUG=all is
* used since they don't affect the behaviour of Cogl they
* simply print out verbose information */
static const GDebugKey cogl_log_debug_keys[] = {
{ "handle", COGL_DEBUG_HANDLE },
{ "slicing", COGL_DEBUG_SLICING },
{ "atlas", COGL_DEBUG_ATLAS },
{ "blend-strings", COGL_DEBUG_BLEND_STRINGS },
{ "journal", COGL_DEBUG_JOURNAL },
{ "batching", COGL_DEBUG_BATCHING },
{ "matrices", COGL_DEBUG_MATRICES },
{ "draw", COGL_DEBUG_DRAW },
{ "opengl", COGL_DEBUG_OPENGL },
{ "pango", COGL_DEBUG_PANGO },
{ "show-source", COGL_DEBUG_SHOW_SOURCE},
{ "offscreen", COGL_DEBUG_OFFSCREEN },
{ "texture-pixmap", COGL_DEBUG_TEXTURE_PIXMAP },
{ "bitmap", COGL_DEBUG_BITMAP },
{ "clipping", COGL_DEBUG_CLIPPING }
};
static const int n_cogl_log_debug_keys =
G_N_ELEMENTS (cogl_log_debug_keys);
static const GDebugKey cogl_behavioural_debug_keys[] = {
{ "rectangles", COGL_DEBUG_RECTANGLES },
{ "disable-batching", COGL_DEBUG_DISABLE_BATCHING },
{ "disable-vbos", COGL_DEBUG_DISABLE_VBOS },
{ "disable-pbos", COGL_DEBUG_DISABLE_PBOS },
{ "disable-software-transform", COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM },
{ "dump-atlas-image", COGL_DEBUG_DUMP_ATLAS_IMAGE },
{ "disable-atlas", COGL_DEBUG_DISABLE_ATLAS },
{ "disable-shared-atlas", COGL_DEBUG_DISABLE_SHARED_ATLAS },
{ "disable-texturing", COGL_DEBUG_DISABLE_TEXTURING},
{ "disable-arbfp", COGL_DEBUG_DISABLE_ARBFP},
{ "disable-fixed", COGL_DEBUG_DISABLE_FIXED},
CoglMaterial: Implements sparse materials design This is a complete overhaul of the data structures used to manage CoglMaterial state. We have these requirements that were aiming to meet: (Note: the references to "renderlists" correspond to the effort to support scenegraph level shuffling of Clutter actor primitives so we can minimize GPU state changes) Sparse State: We wanted a design that allows sparse descriptions of state so it scales well as we make CoglMaterial responsible for more and more state. It needs to scale well in terms of memory usage and the cost of operations we need to apply to materials such as comparing, copying and flushing their state. I.e. we would rather have these things scale by the number of real changes a material represents not by how much overall state CoglMaterial becomes responsible for. Cheap Copies: As we add support for renderlists in Clutter we will need to be able to get an immutable handle for a given material's current state so that we can retain a record of a primitive with its associated material without worrying that changes to the original material will invalidate that record. No more flush override options: We want to get rid of the flush overrides mechanism we currently use to deal with texture fallbacks, wrap mode changes and to handle the use of highlevel CoglTextures that need to be resolved into lowlevel textures before flushing the material state. The flush options structure has been expanding in size and the structure is logged with every journal entry so it is not an approach that scales well at all. It also makes flushing material state that much more complex. Weak Materials: Again for renderlists we need a way to create materials derived from other materials but without the strict requirement that modifications to the original material wont affect the derived ("weak") material. The only requirement is that its possible to later check if the original material has been changed. A summary of the new design: A CoglMaterial now basically represents a diff against its parent. Each material has a single parent and a mask of state that it changes. Each group of state (such as the blending state) has an "authority" which is found by walking up from a given material through its ancestors checking the difference mask until a match for that group is found. There is only one root node to the graph of all materials, which is the default material first created when Cogl is being initialized. All the groups of state are divided into two types, such that infrequently changed state belongs in a separate "BigState" structure that is only allocated and attached to a material when necessary. CoglMaterialLayers are another sparse structure. Like CoglMaterials they represent a diff against their parent and all the layers are part of another graph with the "default_layer_0" layer being the root node that Cogl creates during initialization. Copying a material is now basically just a case of slice allocating a CoglMaterial, setting the parent to be the source being copied and zeroing the mask of changes. Flush overrides should now be handled by simply relying on the cheapness of copying a material and making changes to it. (This will be done in a follow on commit) Weak material support will be added in a follow on commit.
2010-04-08 11:21:04 +00:00
{ "disable-glsl", COGL_DEBUG_DISABLE_GLSL},
{ "disable-blending", COGL_DEBUG_DISABLE_BLENDING},
{ "disable-npot-textures", COGL_DEBUG_DISABLE_NPOT_TEXTURES},
{ "wireframe", COGL_DEBUG_WIREFRAME},
{ "disable-software-clip", COGL_DEBUG_DISABLE_SOFTWARE_CLIP},
{ "disable-program-caches", COGL_DEBUG_DISABLE_PROGRAM_CACHES},
{ "disable-fast-read-pixel", COGL_DEBUG_DISABLE_FAST_READ_PIXEL}
};
static const int n_cogl_behavioural_debug_keys =
G_N_ELEMENTS (cogl_behavioural_debug_keys);
unsigned long _cogl_debug_flags[COGL_DEBUG_N_LONGS];
GHashTable *_cogl_debug_instances;
static void
_cogl_parse_debug_string_for_keys (const char *value,
gboolean enable,
const GDebugKey *keys,
unsigned int nkeys)
{
int long_num, key_num;
/* g_parse_debug_string expects the value field in GDebugKey to be a
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 (long_num = 0; long_num < COGL_DEBUG_N_LONGS; long_num++)
{
int int_num;
for (int_num = 0;
int_num < sizeof (unsigned long) / sizeof (unsigned int);
int_num++)
{
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;
}
}
}
}
void
_cogl_parse_debug_string (const char *value,
gboolean enable,
gboolean ignore_help)
{
if (ignore_help && strcmp (value, "help") == 0)
return;
/* We don't want to let g_parse_debug_string handle "all" because
* literally enabling all the debug options wouldn't be useful to
* anyone; instead the all option enables all non behavioural
* options.
*/
if (strcmp (value, "all") == 0 ||
strcmp (value, "verbose") == 0)
{
int i;
for (i = 0; i < n_cogl_log_debug_keys; i++)
if (enable)
COGL_DEBUG_SET_FLAG (cogl_log_debug_keys[i].value);
else
COGL_DEBUG_CLEAR_FLAG (cogl_log_debug_keys[i].value);
}
else if (g_ascii_strcasecmp (value, "help") == 0)
{
g_printerr ("\n\n%28s\n", _("Supported debug values:"));
profile: Update to uprof-0.3 dep for --enable-profile When building with --enable-profile we now depend on the uprof-0.3 developer release which brings a few improvements: » It lets us "fix" how we initialize uprof so that instead of using a shared object constructor/destructor (which was a hack used when first adding uprof support to Clutter) we can now initialize as part of clutter's normal initialization code. As a side note though, I found that the way Clutter initializes has some quite serious problems whenever it involves GOptionGroups. It is not able to guarantee the initialization of dependencies like uprof and Cogl. For this reason we still use the contructor/destructor approach to initialize uprof in Cogl. » uprof-0.3 provides a better API for adding custom columns when reporting timer and counter statistics which lets us remove quite a lot of manual report generation code in clutter-profile.c. » uprof-0.3 provides a shared context for tracking mainloop timer statistics. This means any mainloop based library following the same "Mainloop" timer naming convention can use the shared context and no matter who ends up owning the final mainloop the statistics will always be in the same place. This allows profiling of Clutter with an external mainloop such as with the Mutter compositor. » uprof-0.3 can export statistics over dbus and comes with an ncurses based ui to vizualize timer and counter stats live. The latest version of uprof can be cloned from: git://github.com/rib/UProf.git
2010-06-21 14:36:46 +00:00
#define OPT(MASK_NAME, GROUP, NAME, NAME_FORMATTED, DESCRIPTION) \
g_printerr ("%28s %s\n", NAME ":", g_dgettext (GETTEXT_PACKAGE, \
DESCRIPTION));
profile: Update to uprof-0.3 dep for --enable-profile When building with --enable-profile we now depend on the uprof-0.3 developer release which brings a few improvements: » It lets us "fix" how we initialize uprof so that instead of using a shared object constructor/destructor (which was a hack used when first adding uprof support to Clutter) we can now initialize as part of clutter's normal initialization code. As a side note though, I found that the way Clutter initializes has some quite serious problems whenever it involves GOptionGroups. It is not able to guarantee the initialization of dependencies like uprof and Cogl. For this reason we still use the contructor/destructor approach to initialize uprof in Cogl. » uprof-0.3 provides a better API for adding custom columns when reporting timer and counter statistics which lets us remove quite a lot of manual report generation code in clutter-profile.c. » uprof-0.3 provides a shared context for tracking mainloop timer statistics. This means any mainloop based library following the same "Mainloop" timer naming convention can use the shared context and no matter who ends up owning the final mainloop the statistics will always be in the same place. This allows profiling of Clutter with an external mainloop such as with the Mutter compositor. » uprof-0.3 can export statistics over dbus and comes with an ncurses based ui to vizualize timer and counter stats live. The latest version of uprof can be cloned from: git://github.com/rib/UProf.git
2010-06-21 14:36:46 +00:00
#include "cogl-debug-options.h"
g_printerr ("\n%28s\n", _("Special debug values:"));
profile: Update to uprof-0.3 dep for --enable-profile When building with --enable-profile we now depend on the uprof-0.3 developer release which brings a few improvements: » It lets us "fix" how we initialize uprof so that instead of using a shared object constructor/destructor (which was a hack used when first adding uprof support to Clutter) we can now initialize as part of clutter's normal initialization code. As a side note though, I found that the way Clutter initializes has some quite serious problems whenever it involves GOptionGroups. It is not able to guarantee the initialization of dependencies like uprof and Cogl. For this reason we still use the contructor/destructor approach to initialize uprof in Cogl. » uprof-0.3 provides a better API for adding custom columns when reporting timer and counter statistics which lets us remove quite a lot of manual report generation code in clutter-profile.c. » uprof-0.3 provides a shared context for tracking mainloop timer statistics. This means any mainloop based library following the same "Mainloop" timer naming convention can use the shared context and no matter who ends up owning the final mainloop the statistics will always be in the same place. This allows profiling of Clutter with an external mainloop such as with the Mutter compositor. » uprof-0.3 can export statistics over dbus and comes with an ncurses based ui to vizualize timer and counter stats live. The latest version of uprof can be cloned from: git://github.com/rib/UProf.git
2010-06-21 14:36:46 +00:00
OPT (IGNORED, "ignored", "all", "ignored", \
N_("Enables all non-behavioural debug options"));
profile: Update to uprof-0.3 dep for --enable-profile When building with --enable-profile we now depend on the uprof-0.3 developer release which brings a few improvements: » It lets us "fix" how we initialize uprof so that instead of using a shared object constructor/destructor (which was a hack used when first adding uprof support to Clutter) we can now initialize as part of clutter's normal initialization code. As a side note though, I found that the way Clutter initializes has some quite serious problems whenever it involves GOptionGroups. It is not able to guarantee the initialization of dependencies like uprof and Cogl. For this reason we still use the contructor/destructor approach to initialize uprof in Cogl. » uprof-0.3 provides a better API for adding custom columns when reporting timer and counter statistics which lets us remove quite a lot of manual report generation code in clutter-profile.c. » uprof-0.3 provides a shared context for tracking mainloop timer statistics. This means any mainloop based library following the same "Mainloop" timer naming convention can use the shared context and no matter who ends up owning the final mainloop the statistics will always be in the same place. This allows profiling of Clutter with an external mainloop such as with the Mutter compositor. » uprof-0.3 can export statistics over dbus and comes with an ncurses based ui to vizualize timer and counter stats live. The latest version of uprof can be cloned from: git://github.com/rib/UProf.git
2010-06-21 14:36:46 +00:00
OPT (IGNORED, "ignored", "verbose", "ignored", \
N_("Enables all non-behavioural debug options"));
#undef OPT
exit (1);
}
else
{
_cogl_parse_debug_string_for_keys (value,
enable,
cogl_log_debug_keys,
n_cogl_log_debug_keys);
_cogl_parse_debug_string_for_keys (value,
enable,
cogl_behavioural_debug_keys,
n_cogl_behavioural_debug_keys);
}
}
#ifdef COGL_ENABLE_DEBUG
static gboolean
cogl_arg_debug_cb (const char *key,
const char *value,
gpointer user_data)
{
_cogl_parse_debug_string (value,
TRUE /* enable the flags */,
FALSE /* don't ignore help */);
return TRUE;
}
static gboolean
cogl_arg_no_debug_cb (const char *key,
cogl: improves header and coding style consistency We've had complaints that our Cogl code/headers are a bit "special" so this is a first pass at tidying things up by giving them some consistency. These changes are all consistent with how new code in Cogl is being written, but the style isn't consistently applied across all code yet. There are two parts to this patch; but since each one required a large amount of effort to maintain tidy indenting it made sense to combine the changes to reduce the time spent re indenting the same lines. The first change is to use a consistent style for declaring function prototypes in headers. Cogl headers now consistently use this style for prototypes: return_type cogl_function_name (CoglType arg0, CoglType arg1); Not everyone likes this style, but it seems that most of the currently active Cogl developers agree on it. The second change is to constrain the use of redundant glib data types in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all been replaced with int, unsigned int, float, long, unsigned long and char respectively. When talking about pixel data; use of guchar has been replaced with guint8, otherwise unsigned char can be used. The glib types that we continue to use for portability are gboolean, gint{8,16,32,64}, guint{8,16,32,64} and gsize. The general intention is that Cogl should look palatable to the widest range of C programmers including those outside the Gnome community so - especially for the public API - we want to minimize the number of foreign looking typedefs.
2010-02-10 01:57:32 +00:00
const char *value,
gpointer user_data)
{
_cogl_parse_debug_string (value,
FALSE, /* disable the flags */
TRUE /* ignore help */);
return TRUE;
}
#endif /* COGL_ENABLE_DEBUG */
static GOptionEntry cogl_args[] = {
#ifdef COGL_ENABLE_DEBUG
{ "cogl-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_debug_cb,
N_("Cogl debugging flags to set"), "FLAGS" },
{ "cogl-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_no_debug_cb,
N_("Cogl debugging flags to unset"), "FLAGS" },
#endif /* COGL_ENABLE_DEBUG */
{ NULL, },
};
void
_cogl_debug_check_environment (void)
{
const char *env_string;
env_string = g_getenv ("COGL_DEBUG");
if (env_string != NULL)
{
_cogl_parse_debug_string (env_string,
TRUE /* enable the flags */,
FALSE /* don't ignore help */);
env_string = NULL;
}
env_string = g_getenv ("COGL_NO_DEBUG");
if (env_string != NULL)
{
_cogl_parse_debug_string (env_string,
FALSE /* disable the flags */,
FALSE /* don't ignore help */);
env_string = NULL;
}
}
static gboolean
pre_parse_hook (GOptionContext *context,
GOptionGroup *group,
gpointer data,
GError **error)
{
_cogl_init ();
return TRUE;
}
/* XXX: GOption based library initialization is not reliable because the
* GOption API has no way to represent dependencies between libraries.
*/
GOptionGroup *
cogl_get_option_group (void)
{
GOptionGroup *group;
group = g_option_group_new ("cogl",
_("Cogl Options"),
_("Show Cogl options"),
NULL, NULL);
g_option_group_set_parse_hooks (group, pre_parse_hook, NULL);
g_option_group_add_entries (group, cogl_args);
g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
return group;
}