diff --git a/README b/README index 48d6ed14e..9bc0974dc 100644 --- a/README +++ b/README @@ -55,7 +55,7 @@ If you want support for profiling Clutter you will also need: UProf is available from: - git://git.moblin.org/uprof.git + git://github.com/rib/UProf.git RESOURCES ------------------------------------------------------------------------------- diff --git a/clutter/clutter-debug.h b/clutter/clutter-debug.h index 75ead7114..209e51a8d 100644 --- a/clutter/clutter-debug.h +++ b/clutter/clutter-debug.h @@ -3,6 +3,7 @@ #include #include "clutter-main.h" +#include "clutter-profile.h" G_BEGIN_DECLS @@ -44,41 +45,45 @@ typedef enum { #ifdef __GNUC__ /* Try the GCC extension for valists in macros */ -#define CLUTTER_NOTE(type,x,a...) G_STMT_START { \ - if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \ - g_message ("[" #type "] " G_STRLOC ": " x, ##a); \ - } } G_STMT_END - -#define CLUTTER_TIMESTAMP(type,x,a...) G_STMT_START { \ - if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \ - g_message ("[" #type "]" " %li:" G_STRLOC ": " \ - x, clutter_get_timestamp(), ##a); \ - } } G_STMT_END +#define CLUTTER_NOTE(type,x,a...) G_STMT_START { \ + if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) \ + { _clutter_profile_trace_message ("[" #type "] " \ + G_STRLOC " & " x, ##a); } \ + } G_STMT_END +#define CLUTTER_TIMESTAMP(type,x,a...) G_STMT_START { \ + if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) \ + { g_message ("[" #type "]" " %li:" G_STRLOC ": " \ + x, clutter_get_timestamp(), ##a); } \ + } G_STMT_END #else /* !__GNUC__ */ - /* Try the C99 version; unfortunately, this does not allow us to pass * empty arguments to the macro, which means we have to * do an intemediate printf. */ -#define CLUTTER_NOTE(type,...) G_STMT_START { \ - if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \ - gchar * _fmt = g_strdup_printf (__VA_ARGS__); \ - g_message ("[" #type "] " G_STRLOC ": %s",_fmt); \ - g_free (_fmt); } } G_STMT_END +#define CLUTTER_NOTE(type,...) G_STMT_START { \ + if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) \ + { \ + gchar * _fmt = g_strdup_printf (__VA_ARGS__); \ + _clutter_profile_trace_message ("[" #type "] " \ + G_STRLOC " & %s",_fmt); \ + g_free (_fmt); \ + } \ + } G_STMT_END -#define CLUTTER_TIMESTAMP(type,...) G_STMT_START { \ - if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) { \ - gchar * _fmt = g_strdup_printf (__VA_ARGS__); \ - g_message ("[" #type "]" " %li:" G_STRLOC ": %s", \ - clutter_get_timestamp(), _fmt); \ - g_free (_fmt); \ - } } G_STMT_END +#define CLUTTER_TIMESTAMP(type,...) G_STMT_START { \ + if (G_UNLIKELY (CLUTTER_HAS_DEBUG (type))) \ + { \ + gchar * _fmt = g_strdup_printf (__VA_ARGS__); \ + g_message ("[" #type "]" " %li:" G_STRLOC ": %s", \ + clutter_get_timestamp(), _fmt); \ + g_free (_fmt); \ + } \ + } G_STMT_END +#endif -#endif /* __GNUC__ */ - -#define CLUTTER_MARK() CLUTTER_NOTE(MISC, "== mark ==") -#define CLUTTER_DBG(x) { a } +#define CLUTTER_MARK() CLUTTER_NOTE(MISC, "== mark ==") +#define CLUTTER_DBG(x) { a } #define CLUTTER_GLERR() G_STMT_START { \ if (clutter_debug_flags & CLUTTER_DEBUG_GL) { \ diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index e156dad95..0768833d6 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -904,13 +904,13 @@ timed_poll (GPollFD *ufds, gint ret; CLUTTER_STATIC_TIMER (poll_timer, "Mainloop", /* parent */ - "poll (idle)", + "Mainloop Idle", "The time spent idle in poll()", 0 /* no application private data */); - CLUTTER_TIMER_START (_clutter_uprof_context, poll_timer); + CLUTTER_TIMER_START (uprof_get_mainloop_context (), poll_timer); ret = prev_poll (ufds, nfsd, timeout_); - CLUTTER_TIMER_STOP (_clutter_uprof_context, poll_timer); + CLUTTER_TIMER_STOP (uprof_get_mainloop_context (), poll_timer); return ret; } #endif @@ -931,7 +931,7 @@ clutter_main (void) 0 /* no application private data */); if (clutter_main_loop_level == 0) - CLUTTER_TIMER_START (_clutter_uprof_context, mainloop_timer); + CLUTTER_TIMER_START (uprof_get_mainloop_context (), mainloop_timer); /* Make sure there is a context */ CLUTTER_CONTEXT (); @@ -981,7 +981,7 @@ clutter_main (void) CLUTTER_MARK (); if (clutter_main_loop_level == 0) - CLUTTER_TIMER_STOP (_clutter_uprof_context, mainloop_timer); + CLUTTER_TIMER_STOP (uprof_get_mainloop_context (), mainloop_timer); } static void @@ -1621,12 +1621,19 @@ clutter_init_real (GError **error) return CLUTTER_INIT_ERROR_BACKEND; #ifdef CLUTTER_ENABLE_PROFILE - { - UProfContext *cogl_context; - cogl_context = uprof_find_context ("Cogl"); - if (cogl_context) - uprof_context_link (_clutter_uprof_context, cogl_context); - } + /* We need to be absolutely sure that uprof has been initialized + * before calling _clutter_uprof_init. uprof_init (NULL, NULL) + * will be a NOP if it has been initialized but it will also + * mean subsequent parsing of the UProf GOptionGroup will have no + * affect. + * + * Sadly GOptionGroup based library initialization is extremly + * fragile by design because GOptionGroups have no notion of + * dependencies and our post_parse_hook may be called before + * the cogl or uprof groups get parsed. + */ + uprof_init (NULL, NULL); + _clutter_uprof_init (); if (clutter_profile_flags & CLUTTER_PROFILE_PICKING_ONLY) _clutter_profile_suspend (); @@ -1995,6 +2002,14 @@ clutter_init_with_args (int *argc, group = cogl_get_option_group (); g_option_context_add_group (context, group); + /* Note: That due to the implementation details of glib's goption + * parsing; cogl and uprof will not actually have there arguments + * parsed before the post_parse_hook is called! */ +#ifdef CLUTTER_ENABLE_PROFILE + group = uprof_get_option_group (); + g_option_context_add_group (context, group); +#endif + if (entries) g_option_context_add_main_entries (context, entries, translation_domain); @@ -2027,6 +2042,9 @@ clutter_parse_args (int *argc, { GOptionContext *option_context; GOptionGroup *clutter_group, *cogl_group; +#ifdef CLUTTER_ENABLE_PROFILE + GOptionGroup *uprof_group; +#endif GError *error = NULL; gboolean ret = TRUE; @@ -2045,6 +2063,11 @@ clutter_parse_args (int *argc, cogl_group = cogl_get_option_group (); g_option_context_add_group (option_context, cogl_group); +#ifdef CLUTTER_ENABLE_PROFILE + uprof_group = uprof_get_option_group (); + g_option_context_add_group (option_context, uprof_group); +#endif + if (!g_option_context_parse (option_context, argc, argv, &error)) { if (error) diff --git a/clutter/clutter-profile.c b/clutter/clutter-profile.c index baffaeca0..f7a5c37ef 100644 --- a/clutter/clutter-profile.c +++ b/clutter/clutter-profile.c @@ -6,7 +6,8 @@ #include UProfContext *_clutter_uprof_context; -#define REPORT_COLUMN0_WIDTH 40 + +static UProfReport *clutter_uprof_report; static gboolean searched_for_gl_uprof_context = FALSE; static UProfContext *gl_uprof_context = NULL; @@ -14,164 +15,245 @@ static UProfContext *gl_uprof_context = NULL; typedef struct _ClutterUProfReportState { gulong n_frames; + float fps; + gulong n_picks; + float msecs_picking; } ClutterUProfReportState; -static void -print_counter (UProfCounterResult *counter, - gpointer data) -{ - ClutterUProfReportState *state = data; - gulong count = uprof_counter_result_get_count (counter); - if (count == 0) - return; - - g_print (" %-*s %-5ld %-5ld\n", REPORT_COLUMN0_WIDTH - 2, - uprof_counter_result_get_name (counter), - uprof_counter_result_get_count (counter), - uprof_counter_result_get_count (counter) / state->n_frames); -} - static char * -print_timer_fields (UProfTimerResult *timer, - guint *fields_width, - gpointer data) +timer_per_frame_cb (UProfReport *report, + UProfTimerResult *timer, + void *user_data) { - ClutterUProfReportState *state = data; - /* Print the field titles when timer == NULL */ - if (!timer) - return g_strdup_printf ("Per Frame"); + ClutterUProfReportState *state = user_data; + int n_frames = state->n_frames ? state->n_frames : 1; return g_strdup_printf ("%-10.2f", uprof_timer_result_get_total_msecs (timer) / - (float)state->n_frames); + (float)n_frames); } -static void -print_report (UProfReport *report, UProfContext *context) +static char * +counter_per_frame_cb (UProfReport *report, + UProfCounterResult *counter, + void *user_data) { - GList *root_timers; - GList *l; - UProfTimerResult *stage_paint_timer; - UProfTimerResult *mainloop_timer; - UProfTimerResult *do_pick_timer; - float fps; - ClutterUProfReportState state; + ClutterUProfReportState *state = user_data; + int n_frames = state->n_frames ? state->n_frames : 1; - /* FIXME: We need to fix the way Clutter initializes the uprof library - * (we don't currently call uprof_init()) and add a mechanism to know - * if uprof_init hasn't been called so we can simply bail out of report - * generation and not print spurious warning about missing timers. - * Probably we can just have uprof_report_print bail out if uprof wasn't - * initialized, so we don't have to care here. - */ - mainloop_timer = uprof_context_get_timer_result (context, "Mainloop"); - stage_paint_timer = uprof_context_get_timer_result (context, "Redrawing"); - do_pick_timer = uprof_context_get_timer_result (context, "Do pick"); + return g_strdup_printf ("%-5ld", + uprof_counter_result_get_count (counter) / + n_frames); +} +static char * +get_n_frames_cb (UProfReport *report, + const char *statistic, + const char *attribute, + void *user_data) +{ + ClutterUProfReportState *state = user_data; + + return g_strdup_printf ("%lu", state->n_frames); +} + +static char * +get_fps_cb (UProfReport *report, + const char *statistic, + const char *attribute, + void *user_data) +{ + ClutterUProfReportState *state = user_data; + + return g_strdup_printf ("%5.2f\n", state->fps); +} + +static char * +get_n_picks_cb (UProfReport *report, + const char *statistic, + const char *attribute, + void *user_data) +{ + ClutterUProfReportState *state = user_data; + + return g_strdup_printf ("%lu", state->n_picks); +} + +static char * +get_picks_per_frame_cb (UProfReport *report, + const char *statistic, + const char *attribute, + void *user_data) +{ + ClutterUProfReportState *state = user_data; + int n_frames = state->n_frames ? state->n_frames : 1; + + return g_strdup_printf ("%3.2f", + (float)state->n_picks / (float)n_frames); +} + +static char * +get_msecs_per_pick_cb (UProfReport *report, + const char *statistic, + const char *attribute, + void *user_data) +{ + ClutterUProfReportState *state = user_data; + int n_picks = state->n_picks ? state->n_picks : 1; + + return g_strdup_printf ("%3.2f", state->msecs_picking / (float)n_picks); +} + +static gboolean +_clutter_uprof_report_prepare (UProfReport *report, + void **closure_ret, + void *user_data) +{ + UProfContext *mainloop_context; + UProfTimerResult *mainloop_timer; + UProfTimerResult *stage_paint_timer; + UProfTimerResult *do_pick_timer; + ClutterUProfReportState *state; + + /* NB: uprof provides a shared context for mainloop statistics which allows + * this to work even if the application and not Clutter owns the mainloop. + * + * This is the case when running Mutter for example but because Mutter will + * follow the same convention of using the shared context then we can always + * be sure of where to look for the mainloop results. */ + mainloop_context = uprof_get_mainloop_context (); + mainloop_timer = uprof_context_get_timer_result (mainloop_context, + "Mainloop"); + /* just bail out if the mainloop timer wasn't hit */ + if (!mainloop_timer) + return FALSE; + + state = g_new0 (ClutterUProfReportState, 1); + *closure_ret = state; + + stage_paint_timer = uprof_context_get_timer_result (_clutter_uprof_context, + "Redrawing"); if (stage_paint_timer) { - g_print ("\n"); + state->n_frames = uprof_timer_result_get_start_count (stage_paint_timer); - state.n_frames = uprof_timer_result_get_start_count (stage_paint_timer); - g_print ("Frame count = %lu\n", state.n_frames); + uprof_report_add_statistic (report, + "Frames", + "Frame count information"); + uprof_report_add_statistic_attribute (report, "Frames", + "Count", "Count", + "The total number of frames", + UPROF_ATTRIBUTE_TYPE_INT, + get_n_frames_cb, + state); - fps = (float) state.n_frames - / (uprof_timer_result_get_total_msecs (mainloop_timer) - / 1000.0); - g_print ("Average fps = %5.2f\n", fps); + + state->fps = (float) state->n_frames + / (uprof_timer_result_get_total_msecs (mainloop_timer) + / 1000.0); + uprof_report_add_statistic_attribute (report, "Frames", + "Average FPS", "Average\nFPS", + "The average frames per second", + UPROF_ATTRIBUTE_TYPE_FLOAT, + get_fps_cb, + state); } + do_pick_timer = uprof_context_get_timer_result (_clutter_uprof_context, + "Picking"); if (do_pick_timer) { - int n_picks = uprof_timer_result_get_start_count (do_pick_timer); + state->n_picks = uprof_timer_result_get_start_count (do_pick_timer); + state->msecs_picking = + uprof_timer_result_get_total_msecs (do_pick_timer); - g_print ("\n"); + uprof_report_add_statistic (report, + "Picks", + "Picking information"); + uprof_report_add_statistic_attribute (report, "Picks", + "Count", "Count", + "The total number of picks", + UPROF_ATTRIBUTE_TYPE_INT, + get_n_picks_cb, + state); - g_print ("Pick Stats:\n"); - g_print ("Pick count = %d\n", n_picks); - g_print ("Average picks per frame = %3.2f\n", - (float)n_picks / (float)state.n_frames); - g_print ("Average Msecs per pick = %3.2f\n", - (float)uprof_timer_result_get_total_msecs (do_pick_timer) - / (float)n_picks); + uprof_report_add_statistic_attribute (report, "Picks", + "Picks Per Frame", + "Picks\nPer Frame", + "The average number of picks " + "per frame", + UPROF_ATTRIBUTE_TYPE_FLOAT, + get_picks_per_frame_cb, + state); + + uprof_report_add_statistic_attribute (report, "Picks", + "Msecs Per Pick", + "Msecs\nPer Pick", + "The average number of " + "milliseconds per pick", + UPROF_ATTRIBUTE_TYPE_FLOAT, + get_msecs_per_pick_cb, + state); } - root_timers = uprof_context_get_root_timer_results (context); - if (!root_timers) - return; + uprof_report_add_counters_attribute (clutter_uprof_report, + "Per Frame", + "Per Frame", + "The number of counts per frame", + UPROF_ATTRIBUTE_TYPE_INT, + counter_per_frame_cb, + state); + uprof_report_add_timers_attribute (clutter_uprof_report, + "Per Frame", + "Per Frame", + "The amount of timer per frame", + UPROF_ATTRIBUTE_TYPE_FLOAT, + timer_per_frame_cb, + state); - g_print ("\n"); - - /* XXX: UProfs default reporting code now supports dynamic sizing for the Name - * column, the only thing it's missing is support for adding custom columns but - * when that's added we should switch away from manual report generation. */ - g_print ("Counters:\n"); - g_print (" %-*s %5s %s\n", REPORT_COLUMN0_WIDTH - 2, "Name", "Total", "Per Frame"); - g_print (" %-*s %5s %s\n", REPORT_COLUMN0_WIDTH - 2, "----", "-----", "---------"); - uprof_context_foreach_counter (context, - UPROF_COUNTER_SORT_COUNT_INC, - print_counter, - &state); - - g_print ("\n"); - g_print ("Timers:\n"); - for (l = root_timers; l != NULL; l = l->next) - uprof_timer_result_print_and_children ((UProfTimerResult *)l->data, - print_timer_fields, - &state); - - g_print ("\n"); + return TRUE; } -/* FIXME: we should be able to deal with creating the uprof context in - * clutter_init instead. I think the only reason I did it this way originally - * was as a quick hack. - */ -static void __attribute__ ((constructor)) -clutter_uprof_constructor (void) -{ - _clutter_uprof_context = uprof_context_new ("Clutter"); -} - -#if 0 static void -print_timers (UProfContext *context) +_clutter_uprof_report_done (UProfReport *report, void *closure, void *user_data) { - GList *root_timers; - GList *l; - - root_timers = uprof_context_get_root_timer_results (); - - root_timers = - g_list_sort_with_data (context->root_timers, - (GCompareDataFunc)_uprof_timer_compare_total_times, - NULL); - for (l = context->timers; l != NULL; l = l->next) - { - UProfTimerState *timer = l->data; - timer->children = - g_list_sort_with_data (timer->children, - (GCompareDataFunc) - _uprof_timer_compare_total_times, - NULL); - } + g_free (closure); } -#endif -static void __attribute__ ((destructor)) -clutter_uprof_destructor (void) +static void +print_exit_report (void) { if (!(clutter_profile_flags & CLUTTER_PROFILE_DISABLE_REPORT)) - { - UProfReport *report = uprof_report_new ("Clutter report"); - uprof_report_add_context (report, _clutter_uprof_context); - uprof_report_add_context_callback (report, print_report); - uprof_report_print (report); - uprof_report_unref (report); - } + uprof_report_print (clutter_uprof_report); + + uprof_report_unref (clutter_uprof_report); + uprof_context_unref (_clutter_uprof_context); } +void +_clutter_uprof_init (void) +{ + UProfContext *cogl_context; + + _clutter_uprof_context = uprof_context_new ("Clutter"); + uprof_context_link (_clutter_uprof_context, uprof_get_mainloop_context ()); + g_atexit (print_exit_report); + + cogl_context = uprof_find_context ("Cogl"); + if (cogl_context) + uprof_context_link (_clutter_uprof_context, cogl_context); + + /* We make the report object up-front so we can use uprof-tool + * to fetch reports at runtime via dbus... */ + clutter_uprof_report = uprof_report_new ("Clutter report"); + uprof_report_add_context (clutter_uprof_report, _clutter_uprof_context); + uprof_report_set_init_fini_callbacks (clutter_uprof_report, + _clutter_uprof_report_prepare, + _clutter_uprof_report_done, + NULL); +} + void _clutter_profile_suspend (void) { @@ -198,5 +280,18 @@ _clutter_profile_resume (void) uprof_context_resume (_clutter_uprof_context); } +void +_clutter_profile_trace_message (const char *format, ...) +{ + va_list ap; + + va_start (ap, format); + g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, ap); + va_end (ap); + + if (_clutter_uprof_context) + uprof_context_vtrace_message (_clutter_uprof_context, format, ap); +} + #endif diff --git a/clutter/clutter-profile.h b/clutter/clutter-profile.h index 00ea77dfb..8f99bab0c 100644 --- a/clutter/clutter-profile.h +++ b/clutter/clutter-profile.h @@ -48,11 +48,17 @@ extern UProfContext *_clutter_uprof_context; #define CLUTTER_TIMER_START UPROF_TIMER_START #define CLUTTER_TIMER_STOP UPROF_TIMER_STOP +void +_clutter_uprof_init (void); + void _clutter_profile_suspend (void); void _clutter_profile_resume (void); +void +_clutter_profile_trace_message (const char *format, ...); + #else /* CLUTTER_ENABLE_PROFILE */ #define CLUTTER_STATIC_TIMER(A,B,C,D,E) extern void _clutter_dummy_decl (void) @@ -65,6 +71,8 @@ _clutter_profile_resume (void); #define _clutter_profile_suspend() G_STMT_START {} G_STMT_END #define _clutter_profile_resume() G_STMT_START {} G_STMT_END +#define _clutter_profile_trace_message g_message + #endif /* CLUTTER_ENABLE_PROFILE */ extern guint clutter_profile_flags; diff --git a/clutter/cogl/cogl/cogl-debug-options.h b/clutter/cogl/cogl/cogl-debug-options.h new file mode 100644 index 000000000..a73d7e1f6 --- /dev/null +++ b/clutter/cogl/cogl/cogl-debug-options.h @@ -0,0 +1,145 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2010 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 . + * + * + */ + +OPT (HANDLE, + "Cogl Tracing", + "ref-counts", + "CoglObject references", + "Debug ref counting issues for CoglObjects") +OPT (SLICING, + "Cogl Tracing", + "slicing", + "Trace Texture Slicing", + "debug the creation of texture slices") +OPT (ATLAS, + "Cogl Tracing", + "atlas", + "Trace Atlas Textures", + "Debug texture atlas management") +OPT (BLEND_STRINGS, + "Cogl Tracing", + "blend-strings", + "Trace Blend Strings", + "Debug CoglBlendString parsing") +OPT (JOURNAL, + "Cogl Tracing", + "journal", + "Trace Journal", + "View all the geometry passing through the journal") +OPT (BATCHING, + "Cogl Tracing", + "batching", + "Trace Batching", + "Show how geometry is being batched in the journal") +OPT (MATRICES, + "Cogl Tracing", + "matrices", + "Trace matrices", + "Trace all matrix manipulation") +/* XXX we should replace the "draw" option its very hand wavy... */ +OPT (DRAW, + "Cogl Tracing", + "draw", + "Trace Misc Drawing", + "Trace some misc drawing operations") +OPT (PANGO, + "Cogl Tracing", + "pango", + "Trace Pango Renderer", + "Trace the Cogl Pango renderer") +OPT (TEXTURE_PIXMAP, + "Cogl Tracing", + "texture-pixmap", + "Trace CoglTexturePixmap backend", + "Trace the Cogl texture pixmap backend") +OPT (RECTANGLES, + "Visualize", + "rectangles", + "Outline rectangles", + "Add wire outlines for all rectangular geometry") +OPT (DISABLE_BATCHING, + "Root Cause", + "disable-batching", + "Disable Journal batching", + "Disable batching of geometry in the Cogl Journal.") +OPT (DISABLE_VBOS, + "Root Cause", + "disable-vbos", + "Disable GL Vertex Buffers", + "Disable use of OpenGL vertex buffer objects") +OPT (DISABLE_PBOS, + "Root Cause", + "disable-pbos", + "Disable GL Pixel Buffers", + "Disable use of OpenGL pixel buffer objects") +OPT (DISABLE_SOFTWARE_TRANSFORM, + "Root Cause", + "disable-software-transform", + "Disable software rect transform", + "Use the GPU to transform rectangular geometry") +OPT (DUMP_ATLAS_IMAGE, + "Cogl Specialist", + "dump-atlas-image", + "Dump atlas images", + "Dump texture atlas changes to an image file") +OPT (DISABLE_ATLAS, + "Root Cause", + "disable-atlas", + "Disable texture atlasing", + "Disable use of texture atlasing") +OPT (DISABLE_TEXTURING, + "Root Cause", + "disable-texturing", + "Disable texturing", + "Disable texturing any primitives") +OPT (DISABLE_ARBFP, + "Root Cause", + "disable-arbfp", + "Disable arbfp", + "Disable use of ARB fragment programs") +OPT (DISABLE_GLSL, + "Root Cause", + "disable-glsl", + "Disable GLSL", + "Disable use of GLSL") +OPT (DISABLE_BLENDING, + "Root Cause", + "disable-blending", + "Disable blending", + "Disable use of blending") +OPT (SHOW_SOURCE, + "Cogl Tracing", + "show-source", + "Show source", + "Show generated ARBfp/GLSL source code") +OPT (OPENGL, + "Cogl Tracing", + "opengl", + "Trace some OpenGL", + "Traces some select OpenGL calls") +OPT (OFFSCREEN, + "Cogl Tracing", + "offscreen", + "Trace offscreen support", + "Debug offscreen support") + diff --git a/clutter/cogl/cogl/cogl-debug.c b/clutter/cogl/cogl/cogl-debug.c index 0dbf7f254..2289af2ab 100644 --- a/clutter/cogl/cogl/cogl-debug.c +++ b/clutter/cogl/cogl/cogl-debug.c @@ -103,37 +103,14 @@ _cogl_parse_debug_string (const char *value, else if (strcmp (value, "help") == 0) { g_printerr ("\n\n%28s\n", "Supported debug values:"); -#define OPT(NAME, HELP) \ - g_printerr ("%28s %s\n", NAME, HELP); - OPT ("handle:", "debug ref counting issues for Cogl objects"); - OPT ("slicing:", "debug the creation of texture slices"); - OPT ("atlas:", "debug texture atlas management"); - OPT ("blend-strings:", "debug blend-string parsing"); - OPT ("journal:", "view all geometry passing through the journal"); - OPT ("batching:", "show how geometry is being batched in the journal"); - OPT ("matrices:", "trace all matrix manipulation"); - /* XXX: we should replace the "draw" option its very hand wavy... */ - OPT ("draw:", "misc tracing of some drawing operations"); - OPT ("pango:", "trace the pango renderer"); - OPT ("texture-pixmap:", "trace the Cogl texture pixmap backend"); - OPT ("rectangles:", "add wire outlines for all rectangular geometry"); - OPT ("disable-batching:", "disable the journal batching"); - OPT ("disable-vbos:", "disable use of OpenGL vertex buffer objects"); - OPT ("disable-pbos:", "disable use of OpenGL pixel buffer objects"); - OPT ("disable-software-transform", - "use the GPU to transform rectangular geometry"); - OPT ("dump-atlas-image:", "dump atlas changes to an image file"); - OPT ("disable-atlas:", "disable texture atlasing"); - OPT ("disable-texturing:", "disable texturing primitives"); - OPT ("disable-arbfp:", "disable use of ARBfp"); - OPT ("disable-glsl:", "disable use of GLSL"); - OPT ("disable-blending:", "disable use of blending"); - OPT ("show-source:", "show generated ARBfp/GLSL"); - OPT ("opengl:", "traces some select OpenGL calls"); - OPT ("offscreen:", "debug offscreen support"); +#define OPT(MASK_NAME, GROUP, NAME, NAME_FORMATTED, DESCRIPTION) \ + g_printerr ("%28s %s\n", NAME ":", DESCRIPTION); +#include "cogl-debug-options.h" g_printerr ("\n%28s\n", "Special debug values:"); - OPT ("all:", "Enables all non-behavioural debug options"); - OPT ("verbose:", "Enables all non-behavioural debug options"); + OPT (IGNORED, "ignored", "all", "ignored", \ + "Enables all non-behavioural debug options"); + OPT (IGNORED, "ignored", "verbose", "ignored", \ + "Enables all non-behavioural debug options"); #undef OPT exit (1); } diff --git a/clutter/cogl/cogl/cogl-debug.h b/clutter/cogl/cogl/cogl-debug.h index 4adc23676..e9029afb2 100644 --- a/clutter/cogl/cogl/cogl-debug.h +++ b/clutter/cogl/cogl/cogl-debug.h @@ -24,6 +24,8 @@ #ifndef __COGL_DEBUG_H__ #define __COGL_DEBUG_H__ +#include "cogl-profile.h" + #include G_BEGIN_DECLS @@ -59,17 +61,17 @@ typedef enum { #ifdef COGL_ENABLE_DEBUG #ifdef __GNUC__ -#define COGL_NOTE(type,x,a...) G_STMT_START { \ - if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) { \ - g_message ("[" #type "] " G_STRLOC ": " x, ##a); \ +#define COGL_NOTE(type,x,a...) G_STMT_START { \ + if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) { \ + _cogl_profile_trace_message ("[" #type "] " G_STRLOC " & " x, ##a); \ } } G_STMT_END #else -#define COGL_NOTE(type,...) G_STMT_START { \ - if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) { \ - char *_fmt = g_strdup_printf (__VA_ARGS__); \ - g_message ("[" #type "] " G_STRLOC ": %s", _fmt); \ - g_free (_fmt); \ +#define COGL_NOTE(type,...) G_STMT_START { \ + if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) { \ + char *_fmt = g_strdup_printf (__VA_ARGS__); \ + _cogl_profile_trace_message ("[" #type "] " G_STRLOC " & %s", _fmt);\ + g_free (_fmt); \ } } G_STMT_END #endif /* __GNUC__ */ diff --git a/clutter/cogl/cogl/cogl-profile.c b/clutter/cogl/cogl/cogl-profile.c index e17acda38..c8d11dd76 100644 --- a/clutter/cogl/cogl/cogl-profile.c +++ b/clutter/cogl/cogl/cogl-profile.c @@ -2,16 +2,51 @@ #ifdef COGL_ENABLE_PROFILE #include "cogl-profile.h" +#include "cogl-debug.h" #include UProfContext *_cogl_uprof_context; +static gboolean +debug_option_getter (void *user_data) +{ + unsigned int shift = GPOINTER_TO_UINT (user_data); + return (cogl_debug_flags & (1 << shift)) ? TRUE : FALSE; +} + +static void +debug_option_setter (gboolean value, void *user_data) +{ + unsigned int shift = GPOINTER_TO_UINT (user_data); + + if (value) + cogl_debug_flags |= (1 << shift); + else + cogl_debug_flags &= ~(1 << shift); +} static void __attribute__ ((constructor)) cogl_uprof_constructor (void) { _cogl_uprof_context = uprof_context_new ("Cogl"); +#define OPT(MASK_NAME, GROUP, NAME, NAME_FORMATTED, DESCRIPTION) \ + G_STMT_START { \ + int shift; \ + for (shift = 0; (COGL_DEBUG_ ## MASK_NAME >> shift) != 1; shift++) \ + ; \ + uprof_context_add_boolean_option (_cogl_uprof_context, \ + GROUP, \ + NAME, \ + NAME_FORMATTED, \ + DESCRIPTION, \ + debug_option_getter, \ + debug_option_setter, \ + GUINT_TO_POINTER (shift)); \ + } G_STMT_END; + +#include "cogl-debug-options.h" +#undef OPT } static void __attribute__ ((destructor)) @@ -27,4 +62,17 @@ cogl_uprof_destructor (void) uprof_context_unref (_cogl_uprof_context); } +void +_cogl_profile_trace_message (const char *format, ...) +{ + va_list ap; + + va_start (ap, format); + g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, format, ap); + va_end (ap); + + if (_cogl_uprof_context) + uprof_context_vtrace_message (_cogl_uprof_context, format, ap); +} + #endif diff --git a/clutter/cogl/cogl/cogl-profile.h b/clutter/cogl/cogl/cogl-profile.h index a918e44b8..5473dd67a 100644 --- a/clutter/cogl/cogl/cogl-profile.h +++ b/clutter/cogl/cogl/cogl-profile.h @@ -38,6 +38,9 @@ extern UProfContext *_cogl_uprof_context; #define COGL_TIMER_START UPROF_TIMER_START #define COGL_TIMER_STOP UPROF_TIMER_STOP +void +_cogl_profile_trace_message (const char *format, ...); + #else #define COGL_STATIC_TIMER(A,B,C,D,E) extern void _cogl_dummy_decl (void) @@ -47,6 +50,7 @@ extern UProfContext *_cogl_uprof_context; #define COGL_TIMER_START(A,B) G_STMT_START{ (void)0; }G_STMT_END #define COGL_TIMER_STOP(A,B) G_STMT_START{ (void)0; }G_STMT_END +#define _cogl_profile_trace_message g_message #endif diff --git a/clutter/cogl/cogl/cogl-texture-3d.c b/clutter/cogl/cogl/cogl-texture-3d.c index b684fb3c2..d6d705020 100644 --- a/clutter/cogl/cogl/cogl-texture-3d.c +++ b/clutter/cogl/cogl/cogl-texture-3d.c @@ -35,6 +35,7 @@ #include "cogl-context.h" #include "cogl-handle.h" #include "cogl-journal-private.h" +#include "cogl-material-private.h" #include "cogl-material-opengl-private.h" #include diff --git a/configure.ac b/configure.ac index 322a4d536..92c00fc26 100644 --- a/configure.ac +++ b/configure.ac @@ -942,7 +942,7 @@ AS_CASE([$enable_profile], [ AS_IF([test "x$GCC" = "xyes"], [ - PKG_CHECK_MODULES([PROFILE_DEP], [uprof-0.2]) + PKG_CHECK_MODULES([PROFILE_DEP], [uprof-0.3]) CLUTTER_PROFILE_CFLAGS=" -DCLUTTER_ENABLE_PROFILE -DCOGL_ENABLE_PROFILE $PROFILE_DEP_CFLAGS" CLUTTER_PROFILE_LDFLAGS=" $PROFILE_DEP_LIBS"