+ stage->stall_group_index = group_index;
+ stage->stall_counter_index = counter_index;
+ }
+
+ free (stage_name);
+}
+
+void
+metrics_info_init (void)
+{
+ unsigned i, j;
+ GLuint *group_ids;
+ metrics_info_t *info = ¤t_context.metrics_info;
+
+ glGetPerfMonitorGroupsAMD ((int *) &info->num_groups, 0, NULL);
+
+ group_ids = xmalloc (info->num_groups * sizeof (GLuint));
+
+ glGetPerfMonitorGroupsAMD (NULL, info->num_groups, group_ids);
+
+ info->groups = xmalloc (info->num_groups * sizeof (metrics_group_info_t));
+
+ for (i = 0; i < info->num_groups; i++)
+ metrics_group_info_init (&info->groups[i], group_ids[i]);
+
+ free (group_ids);
+
+ /* Identify each shader stage (by looking at
+ * performance-counter names for specific patterns) and
+ * initialize structures referring to the corresponding
+ * counter numbers for each stage. */
+ info->num_shader_stages = 0;
+ info->stages = NULL;
+
+ for (i = 0; i < info->num_groups; i++) {
+ metrics_group_info_t *group = &info->groups[i];
+ for (j = 0; j < group->num_counters; j++) {
+ char *name = group->counter_names[j];
+ if (strstr (name, "Shader Active Time")) {
+ _add_shader_stage (info, name, i, j,
+ SHADER_ACTIVE);
+ }
+ if (strstr (name, "Shader Stall Time")) {
+ _add_shader_stage (info, name, i, j,
+ SHADER_STALL);
+ }
+ }
+ }
+
+ info->initialized = 1;
+}
+
+void
+metrics_info_fini (void)
+{
+ context_t *ctx = ¤t_context;
+ metrics_info_t *info = &ctx->metrics_info;
+ unsigned i;
+ timer_query_t *timer, *timer_next;
+ monitor_t *monitor, *monitor_next;
+
+ if (! info->initialized)
+ return;
+
+ if (ctx->timer_begun_id) {
+ ctx->timer_begun_id = 0;
+ }
+
+ for (timer = ctx->timer_head;
+ timer;
+ timer = timer_next)
+ {
+ timer_next = timer->next;
+ free (timer);
+ }
+ ctx->timer_head = NULL;
+ ctx->timer_tail = NULL;
+
+ if (ctx->monitor_begun_id) {
+ ctx->monitor_begun_id = 0;
+ }
+
+ for (monitor = ctx->monitor_head;
+ monitor;
+ monitor = monitor_next)
+ {
+ monitor_next = monitor->next;
+ free (monitor);
+ }
+ ctx->monitor_head = NULL;
+ ctx->monitor_tail = NULL;
+
+ current_context.monitors_in_flight = 0;
+
+ for (i = 0; i < info->num_groups; i++)
+ metrics_group_info_fini (&info->groups[i]);
+
+ free (info->groups);
+ info->groups = NULL;
+
+ for (i = 0; i < info->num_shader_stages; i++)
+ free (info->stages[i].name);
+
+ free (info->stages);
+ info->stages = NULL;
+
+ info->initialized = 0;
+}
+
+static const char *
+metrics_op_string (metrics_op_t op)
+{
+ if (op >= METRICS_OP_SHADER)
+ return "Shader program";
+
+ switch (op)
+ {
+ case METRICS_OP_ACCUM:
+ return "glAccum*(+)";
+ case METRICS_OP_BUFFER_DATA:
+ return "glBufferData(+)";
+ case METRICS_OP_BUFFER_SUB_DATA:
+ return "glCopyBufferSubData*";
+ case METRICS_OP_BITMAP:
+ return "glBitmap*";
+ case METRICS_OP_BLIT_FRAMEBUFFER:
+ return "glBlitFramebuffer*";
+ case METRICS_OP_CLEAR:
+ return "glClear(+)";
+ case METRICS_OP_CLEAR_BUFFER_DATA:
+ return "glCearBufferData(+)";
+ case METRICS_OP_CLEAR_TEX_IMAGE:
+ return "glClearTexImage(+)";
+ case METRICS_OP_COPY_PIXELS:
+ return "glCopyPixels";
+ case METRICS_OP_COPY_TEX_IMAGE:
+ return "glCopyTexImage(+)";
+ case METRICS_OP_DRAW_PIXELS:
+ return "glDrawPixels";
+ case METRICS_OP_GET_TEX_IMAGE:
+ return "glGetTexImage(+)";
+ case METRICS_OP_READ_PIXELS:
+ return "glReadPixels*";
+ case METRICS_OP_TEX_IMAGE:
+ return "glTexImage*(+)";
+ default:
+ fprintf (stderr, "fips: Internal error: "
+ "Unknown metrics op value: %d\n", op);
+ exit (1);