1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2008,2009,2010,2011 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  * Authors:
31  *   Robert Bragg <robert@linux.intel.com>
32  */
33 
34 #include "cogl-config.h"
35 
36 #include "cogl-context-private.h"
37 #include "cogl-pipeline-private.h"
38 #include "cogl-pipeline-layer-private.h"
39 #include "cogl-node-private.h"
40 
41 #include <glib.h>
42 
43 typedef struct
44 {
45   int parent_id;
46   int *node_id_ptr;
47   GString *graph;
48   int indent;
49 } PrintDebugState;
50 
51 static gboolean
dump_layer_cb(CoglNode * node,void * user_data)52 dump_layer_cb (CoglNode *node, void *user_data)
53 {
54   CoglPipelineLayer *layer = COGL_PIPELINE_LAYER (node);
55   PrintDebugState *state = user_data;
56   int layer_id = *state->node_id_ptr;
57   PrintDebugState state_out;
58   GString *changes_label;
59   gboolean changes = FALSE;
60 
61   if (state->parent_id >= 0)
62     g_string_append_printf (state->graph, "%*slayer%p -> layer%p;\n",
63                             state->indent, "",
64                             layer->_parent.parent,
65                             layer);
66 
67   g_string_append_printf (state->graph,
68                           "%*slayer%p [label=\"layer=0x%p\\n"
69                           "ref count=%d\" "
70                           "color=\"blue\"];\n",
71                           state->indent, "",
72                           layer,
73                           layer,
74                           COGL_OBJECT (layer)->ref_count);
75 
76   changes_label = g_string_new ("");
77   g_string_append_printf (changes_label,
78                           "%*slayer%p -> layer_state%d [weight=100];\n"
79                           "%*slayer_state%d [shape=box label=\"",
80                           state->indent, "",
81                           layer,
82                           layer_id,
83                           state->indent, "",
84                           layer_id);
85 
86   if (layer->differences & COGL_PIPELINE_LAYER_STATE_UNIT)
87     {
88       changes = TRUE;
89       g_string_append_printf (changes_label,
90                               "\\lunit=%u\\n",
91                               layer->unit_index);
92     }
93 
94   if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
95     {
96       changes = TRUE;
97       g_string_append_printf (changes_label,
98                               "\\ltexture=%p\\n",
99                               layer->texture);
100     }
101 
102   if (changes)
103     {
104       g_string_append_printf (changes_label, "\"];\n");
105       g_string_append (state->graph, changes_label->str);
106       g_string_free (changes_label, TRUE);
107     }
108 
109   state_out.parent_id = layer_id;
110 
111   state_out.node_id_ptr = state->node_id_ptr;
112   (*state_out.node_id_ptr)++;
113 
114   state_out.graph = state->graph;
115   state_out.indent = state->indent + 2;
116 
117   _cogl_pipeline_node_foreach_child (COGL_NODE (layer),
118                                      dump_layer_cb,
119                                      &state_out);
120 
121   return TRUE;
122 }
123 
124 static gboolean
dump_layer_ref_cb(CoglPipelineLayer * layer,void * data)125 dump_layer_ref_cb (CoglPipelineLayer *layer, void *data)
126 {
127   PrintDebugState *state = data;
128   int pipeline_id = *state->node_id_ptr;
129 
130   g_string_append_printf (state->graph,
131                           "%*spipeline_state%d -> layer%p;\n",
132                           state->indent, "",
133                           pipeline_id,
134                           layer);
135 
136   return TRUE;
137 }
138 
139 static gboolean
dump_pipeline_cb(CoglNode * node,void * user_data)140 dump_pipeline_cb (CoglNode *node, void *user_data)
141 {
142   CoglPipeline *pipeline = COGL_PIPELINE (node);
143   PrintDebugState *state = user_data;
144   int pipeline_id = *state->node_id_ptr;
145   PrintDebugState state_out;
146   GString *changes_label;
147   gboolean changes = FALSE;
148   gboolean layers = FALSE;
149 
150   if (state->parent_id >= 0)
151     g_string_append_printf (state->graph, "%*spipeline%d -> pipeline%d;\n",
152                             state->indent, "",
153                             state->parent_id,
154                             pipeline_id);
155 
156   g_string_append_printf (state->graph,
157                           "%*spipeline%d [label=\"pipeline=0x%p\\n"
158                           "ref count=%d\\n"
159                           "breadcrumb=\\\"%s\\\"\" color=\"red\"];\n",
160                           state->indent, "",
161                           pipeline_id,
162                           pipeline,
163                           COGL_OBJECT (pipeline)->ref_count,
164                           pipeline->has_static_breadcrumb ?
165 #ifdef COGL_DEBUG_ENABLED
166                           pipeline->static_breadcrumb : "NULL"
167 #else
168                           "NULL"
169 #endif
170                           );
171 
172   changes_label = g_string_new ("");
173   g_string_append_printf (changes_label,
174                           "%*spipeline%d -> pipeline_state%d [weight=100];\n"
175                           "%*spipeline_state%d [shape=box label=\"",
176                           state->indent, "",
177                           pipeline_id,
178                           pipeline_id,
179                           state->indent, "",
180                           pipeline_id);
181 
182 
183   if (pipeline->differences & COGL_PIPELINE_STATE_COLOR)
184     {
185       changes = TRUE;
186       g_string_append_printf (changes_label,
187                               "\\lcolor=0x%02X%02X%02X%02X\\n",
188                               cogl_color_get_red_byte (&pipeline->color),
189                               cogl_color_get_green_byte (&pipeline->color),
190                               cogl_color_get_blue_byte (&pipeline->color),
191                               cogl_color_get_alpha_byte (&pipeline->color));
192     }
193 
194   if (pipeline->differences & COGL_PIPELINE_STATE_BLEND)
195     {
196       changes = TRUE;
197       g_string_append_printf (changes_label,
198                               "\\lblend\\n");
199     }
200 
201   if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
202     {
203       changes = TRUE;
204       layers = TRUE;
205       g_string_append_printf (changes_label, "\\ln_layers=%d\\n",
206                               pipeline->n_layers);
207     }
208 
209   if (changes)
210     {
211       g_string_append_printf (changes_label, "\"];\n");
212       g_string_append (state->graph, changes_label->str);
213       g_string_free (changes_label, TRUE);
214     }
215 
216   if (layers)
217     {
218       g_list_foreach (pipeline->layer_differences,
219                       (GFunc)dump_layer_ref_cb,
220                       state);
221     }
222 
223   state_out.parent_id = pipeline_id;
224 
225   state_out.node_id_ptr = state->node_id_ptr;
226   (*state_out.node_id_ptr)++;
227 
228   state_out.graph = state->graph;
229   state_out.indent = state->indent + 2;
230 
231   _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
232                                      dump_pipeline_cb,
233                                      &state_out);
234 
235   return TRUE;
236 }
237 
238 /* This function is just here to be called from GDB so we don't really
239    want to put a declaration in a header and we just add it here to
240    avoid a warning */
241 void
242 _cogl_debug_dump_pipelines_dot_file (const char *filename);
243 
244 void
_cogl_debug_dump_pipelines_dot_file(const char * filename)245 _cogl_debug_dump_pipelines_dot_file (const char *filename)
246 {
247   GString *graph;
248   PrintDebugState layer_state;
249   PrintDebugState pipeline_state;
250   int layer_id = 0;
251   int pipeline_id = 0;
252 
253   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
254 
255   if (!ctx->default_pipeline)
256     return;
257 
258   graph = g_string_new ("");
259   g_string_append_printf (graph, "digraph {\n");
260 
261   layer_state.graph = graph;
262   layer_state.parent_id = -1;
263   layer_state.node_id_ptr = &layer_id;
264   layer_state.indent = 0;
265   dump_layer_cb ((CoglNode *)ctx->default_layer_0, &layer_state);
266 
267   pipeline_state.graph = graph;
268   pipeline_state.parent_id = -1;
269   pipeline_state.node_id_ptr = &pipeline_id;
270   pipeline_state.indent = 0;
271   dump_pipeline_cb ((CoglNode *)ctx->default_pipeline, &pipeline_state);
272 
273   g_string_append_printf (graph, "}\n");
274 
275   if (filename)
276     g_file_set_contents (filename, graph->str, -1, NULL);
277   else
278     g_print ("%s", graph->str);
279 
280   g_string_free (graph, TRUE);
281 }
282