1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2009 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  *
29  */
30 
31 #include "cogl-config.h"
32 
33 #include <stdlib.h>
34 
35 #include "cogl-i18n-private.h"
36 #include "cogl-private.h"
37 #include "cogl-debug.h"
38 #include "cogl1-context.h"
39 
40 /* XXX: If you add a debug option, please also add an option
41  * definition to cogl-debug-options.h. This will enable us - for
42  * example - to emit a "help" description for the option.
43  */
44 
45 /* NB: Only these options get enabled if COGL_DEBUG=all is
46  * used since they don't affect the behaviour of Cogl they
47  * simply print out verbose information */
48 static const GDebugKey cogl_log_debug_keys[] = {
49   { "object", COGL_DEBUG_OBJECT },
50   { "slicing", COGL_DEBUG_SLICING },
51   { "atlas", COGL_DEBUG_ATLAS },
52   { "blend-strings", COGL_DEBUG_BLEND_STRINGS },
53   { "journal", COGL_DEBUG_JOURNAL },
54   { "batching", COGL_DEBUG_BATCHING },
55   { "matrices", COGL_DEBUG_MATRICES },
56   { "draw", COGL_DEBUG_DRAW },
57   { "opengl", COGL_DEBUG_OPENGL },
58   { "pango", COGL_DEBUG_PANGO },
59   { "show-source", COGL_DEBUG_SHOW_SOURCE},
60   { "framebuffer", COGL_DEBUG_FRAMEBUFFER },
61   { "offscreen", COGL_DEBUG_OFFSCREEN },
62   { "texture-pixmap", COGL_DEBUG_TEXTURE_PIXMAP },
63   { "bitmap", COGL_DEBUG_BITMAP },
64   { "clipping", COGL_DEBUG_CLIPPING },
65   { "winsys", COGL_DEBUG_WINSYS },
66   { "performance", COGL_DEBUG_PERFORMANCE },
67   { "textures", COGL_DEBUG_TEXTURES },
68 };
69 static const int n_cogl_log_debug_keys =
70   G_N_ELEMENTS (cogl_log_debug_keys);
71 
72 static const GDebugKey cogl_behavioural_debug_keys[] = {
73   { "rectangles", COGL_DEBUG_RECTANGLES },
74   { "disable-batching", COGL_DEBUG_DISABLE_BATCHING },
75   { "disable-pbos", COGL_DEBUG_DISABLE_PBOS },
76   { "disable-software-transform", COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM },
77   { "dump-atlas-image", COGL_DEBUG_DUMP_ATLAS_IMAGE },
78   { "disable-atlas", COGL_DEBUG_DISABLE_ATLAS },
79   { "disable-shared-atlas", COGL_DEBUG_DISABLE_SHARED_ATLAS },
80   { "disable-texturing", COGL_DEBUG_DISABLE_TEXTURING},
81   { "disable-blending", COGL_DEBUG_DISABLE_BLENDING},
82   { "wireframe", COGL_DEBUG_WIREFRAME},
83   { "disable-software-clip", COGL_DEBUG_DISABLE_SOFTWARE_CLIP},
84   { "disable-program-caches", COGL_DEBUG_DISABLE_PROGRAM_CACHES},
85   { "disable-fast-read-pixel", COGL_DEBUG_DISABLE_FAST_READ_PIXEL},
86   { "sync-primitive", COGL_DEBUG_SYNC_PRIMITIVE },
87   { "sync-frame", COGL_DEBUG_SYNC_FRAME},
88   { "stencilling", COGL_DEBUG_STENCILLING },
89 };
90 static const int n_cogl_behavioural_debug_keys =
91   G_N_ELEMENTS (cogl_behavioural_debug_keys);
92 
93 unsigned long _cogl_debug_flags[COGL_DEBUG_N_LONGS];
94 GHashTable *_cogl_debug_instances;
95 
96 static void
_cogl_parse_debug_string_for_keys(const char * value,gboolean enable,const GDebugKey * keys,unsigned int nkeys)97 _cogl_parse_debug_string_for_keys (const char *value,
98                                    gboolean enable,
99                                    const GDebugKey *keys,
100                                    unsigned int nkeys)
101 {
102   int long_num, key_num;
103 
104   /* g_parse_debug_string expects the value field in GDebugKey to be a
105      mask in an unsigned int but the flags are stored in an array of
106      multiple longs so we need to build a separate array for each
107      possible unsigned int */
108 
109   for (long_num = 0; long_num < COGL_DEBUG_N_LONGS; long_num++)
110     {
111       int int_num;
112 
113       for (int_num = 0;
114            int_num < sizeof (unsigned long) / sizeof (unsigned int);
115            int_num++)
116         {
117           GDebugKey keys_for_int[sizeof (unsigned int) * 8];
118           int nkeys_for_int = 0;
119 
120           for (key_num = 0; key_num < nkeys; key_num++)
121             {
122               int long_index = COGL_FLAGS_GET_INDEX (keys[key_num].value);
123               int int_index = (keys[key_num].value %
124                                (sizeof (unsigned long) * 8) /
125                                (sizeof (unsigned int) * 8));
126 
127               if (long_index == long_num && int_index == int_num)
128                 {
129                   keys_for_int[nkeys_for_int] = keys[key_num];
130                   keys_for_int[nkeys_for_int].value =
131                     COGL_FLAGS_GET_MASK (keys[key_num].value) >>
132                     (int_num * sizeof (unsigned int) * 8);
133                   nkeys_for_int++;
134                 }
135             }
136 
137           if (nkeys_for_int > 0)
138             {
139               unsigned long mask =
140                 ((unsigned long) g_parse_debug_string (value,
141                                                        keys_for_int,
142                                                        nkeys_for_int)) <<
143                 (int_num * sizeof (unsigned int) * 8);
144 
145               if (enable)
146                 _cogl_debug_flags[long_num] |= mask;
147               else
148                 _cogl_debug_flags[long_num] &= ~mask;
149             }
150         }
151     }
152 }
153 
154 void
_cogl_parse_debug_string(const char * value,gboolean enable,gboolean ignore_help)155 _cogl_parse_debug_string (const char *value,
156                           gboolean enable,
157                           gboolean ignore_help)
158 {
159   if (ignore_help && strcmp (value, "help") == 0)
160     return;
161 
162   /* We don't want to let g_parse_debug_string handle "all" because
163    * literally enabling all the debug options wouldn't be useful to
164    * anyone; instead the all option enables all non behavioural
165    * options.
166    */
167   if (strcmp (value, "all") == 0 ||
168       strcmp (value, "verbose") == 0)
169     {
170       int i;
171       for (i = 0; i < n_cogl_log_debug_keys; i++)
172         if (enable)
173           COGL_DEBUG_SET_FLAG (cogl_log_debug_keys[i].value);
174         else
175           COGL_DEBUG_CLEAR_FLAG (cogl_log_debug_keys[i].value);
176     }
177   else if (g_ascii_strcasecmp (value, "help") == 0)
178     {
179       g_printerr ("\n\n%28s\n", _("Supported debug values:"));
180 #define OPT(MASK_NAME, GROUP, NAME, NAME_FORMATTED, DESCRIPTION) \
181       g_printerr ("%28s %s\n", NAME ":", DESCRIPTION);
182 #include "cogl-debug-options.h"
183       g_printerr ("\n%28s\n", _("Special debug values:"));
184       OPT (IGNORED, "ignored", "all", "ignored", \
185            N_("Enables all non-behavioural debug options"));
186       OPT (IGNORED, "ignored", "verbose", "ignored", \
187            N_("Enables all non-behavioural debug options"));
188 #undef OPT
189 
190       g_printerr ("\n"
191                   "%28s\n"
192                   " COGL_DISABLE_GL_EXTENSIONS: %s\n"
193                   "   COGL_OVERRIDE_GL_VERSION: %s\n",
194                   _("Additional environment variables:"),
195                   _("Comma-separated list of GL extensions to pretend are "
196                     "disabled"),
197                   _("Override the GL version that Cogl will assume the driver "
198                     "supports"));
199       exit (1);
200     }
201   else
202     {
203       _cogl_parse_debug_string_for_keys (value,
204                                          enable,
205                                          cogl_log_debug_keys,
206                                          n_cogl_log_debug_keys);
207       _cogl_parse_debug_string_for_keys (value,
208                                          enable,
209                                          cogl_behavioural_debug_keys,
210                                          n_cogl_behavioural_debug_keys);
211     }
212 }
213 
214 #ifdef COGL_ENABLE_DEBUG
215 static gboolean
cogl_arg_debug_cb(const char * key,const char * value,void * user_data)216 cogl_arg_debug_cb (const char *key,
217                    const char *value,
218                    void *user_data)
219 {
220   _cogl_parse_debug_string (value,
221                             TRUE /* enable the flags */,
222                             FALSE /* don't ignore help */);
223   return TRUE;
224 }
225 
226 static gboolean
cogl_arg_no_debug_cb(const char * key,const char * value,void * user_data)227 cogl_arg_no_debug_cb (const char *key,
228                       const char *value,
229                       void *user_data)
230 {
231   _cogl_parse_debug_string (value,
232                             FALSE, /* disable the flags */
233                             TRUE /* ignore help */);
234   return TRUE;
235 }
236 #endif /* COGL_ENABLE_DEBUG */
237 
238 static GOptionEntry cogl_args[] = {
239 #ifdef COGL_ENABLE_DEBUG
240   { "cogl-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_debug_cb,
241     N_("Cogl debugging flags to set"), "FLAGS" },
242   { "cogl-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, cogl_arg_no_debug_cb,
243     N_("Cogl debugging flags to unset"), "FLAGS" },
244 #endif /* COGL_ENABLE_DEBUG */
245   { NULL, },
246 };
247 
248 void
_cogl_debug_check_environment(void)249 _cogl_debug_check_environment (void)
250 {
251   const char *env_string;
252 
253   env_string = g_getenv ("COGL_DEBUG");
254   if (env_string != NULL)
255     {
256       _cogl_parse_debug_string (env_string,
257                                 TRUE /* enable the flags */,
258                                 FALSE /* don't ignore help */);
259       env_string = NULL;
260     }
261 
262   env_string = g_getenv ("COGL_NO_DEBUG");
263   if (env_string != NULL)
264     {
265       _cogl_parse_debug_string (env_string,
266                                 FALSE /* disable the flags */,
267                                 FALSE /* don't ignore help */);
268       env_string = NULL;
269     }
270 }
271 
272 static gboolean
pre_parse_hook(GOptionContext * context,GOptionGroup * group,void * data,GError ** error)273 pre_parse_hook (GOptionContext *context,
274                 GOptionGroup *group,
275                 void *data,
276                 GError **error)
277 {
278   _cogl_init ();
279 
280   return TRUE;
281 }
282 
283 /* XXX: GOption based library initialization is not reliable because the
284  * GOption API has no way to represent dependencies between libraries.
285  */
286 GOptionGroup *
cogl_get_option_group(void)287 cogl_get_option_group (void)
288 {
289   GOptionGroup *group;
290 
291   group = g_option_group_new ("cogl",
292                               _("Cogl Options"),
293                               _("Show Cogl options"),
294                               NULL, NULL);
295 
296   g_option_group_set_parse_hooks (group, pre_parse_hook, NULL);
297   g_option_group_add_entries (group, cogl_args);
298 
299   return group;
300 }
301