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