+ return &ctx->op_metrics[op];
+}
+
+static void
+accumulate_program_metrics (metrics_op_t op, GLuint *result, GLuint size)
+{
+#define CONSUME(var) \
+ if (p + sizeof(var) > ((unsigned char *) result) + size) \
+ { \
+ fprintf (stderr, "Unexpected end-of-buffer while " \
+ "parsing results\n"); \
+ break; \
+ } \
+ (var) = *((typeof(var) *) p); \
+ p += sizeof(var);
+
+ context_t *ctx = context_get_current ();
+ metrics_info_t *info = &ctx->metrics_info;
+ op_metrics_t *metrics = ctx_get_op_metrics (ctx, op);
+ unsigned char *p = (unsigned char *) result;
+
+ while (p < ((unsigned char *) result) + size)
+ {
+ GLuint group_id, group_index;
+ GLuint counter_id, counter_index;
+ metrics_group_info_t *group;
+ double value;
+ unsigned i;
+
+ CONSUME (group_id);
+ CONSUME (counter_id);
+
+ for (i = 0; i < info->num_groups; i++) {
+ if (info->groups[i].id == group_id)
+ break;
+ }
+ group_index = i;
+ assert (group_index < info->num_groups);
+ group = &info->groups[group_index];
+
+ for (i = 0; i < group->num_counters; i++) {
+ if (group->counter_ids[i] == counter_id)
+ break;
+ }
+ counter_index = i;
+ assert (counter_index < group->num_counters);
+
+ switch (group->counter_types[counter_index])
+ {
+ uint uint_value;
+ uint64_t uint64_value;
+ float float_value;
+ case GL_UNSIGNED_INT:
+ CONSUME (uint_value);
+ value = uint_value;
+ break;
+ case GL_UNSIGNED_INT64_AMD:
+ CONSUME (uint64_value);
+ value = uint64_value;
+ break;
+ case GL_PERCENTAGE_AMD:
+ case GL_FLOAT:
+ CONSUME (float_value);
+ value = float_value;
+ break;
+ default:
+ fprintf (stderr, "fips: Warning: Unknown counter value type (%d)\n",
+ group->counter_types[counter_index]);
+ value = 0.0;
+ break;
+ }
+
+ metrics->counters[group_index][counter_index] += value;
+ }
+}
+
+static void
+accumulate_program_time (metrics_op_t op, unsigned time_ns)
+{
+ context_t *ctx = context_get_current ();
+ op_metrics_t *metrics;
+
+ metrics = ctx_get_op_metrics (ctx, op);
+
+ metrics->time_ns += time_ns;
+}
+
+typedef struct per_stage_metrics
+{
+ op_metrics_t *metrics;
+ shader_stage_info_t *stage;
+ double time_ns;
+ double active;
+} per_stage_metrics_t;
+
+static int
+_is_shader_stage_counter (metrics_info_t *info,
+ unsigned group_index,
+ unsigned counter_index)
+{
+ shader_stage_info_t *stage;
+ unsigned i;
+
+ for (i = 0; i < info->num_shader_stages; i++) {
+ stage = &info->stages[i];
+
+ if (stage->active_group_index == group_index &&
+ stage->active_counter_index == counter_index)
+ {
+ return 1;
+ }
+
+ if (stage->stall_group_index == group_index &&
+ stage->stall_counter_index == counter_index)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+print_per_stage_metrics (context_t *ctx,
+ per_stage_metrics_t *per_stage,
+ double total)
+{
+ metrics_info_t *info = &ctx->metrics_info;
+ op_metrics_t *metric = per_stage->metrics;
+ metrics_group_info_t *group;
+ const char *op_string;
+ unsigned group_index, counter;
+ double value;
+
+ /* Don't print anything for stages with no alloted time. */
+ if (per_stage->time_ns == 0.0)
+ return;
+
+ op_string = metrics_op_string (metric->op);
+
+ printf ("%21s", op_string);
+
+ if (metric->op >= METRICS_OP_SHADER) {
+ printf (" %3d", metric->op - METRICS_OP_SHADER);
+ } else {
+ printf (" ");
+
+ }
+
+ if (per_stage->stage)
+ printf (" %cS:", per_stage->stage->name[0]);
+ else
+ printf (" :");
+
+ printf ("\t%7.2f ms (%4.1f%%)",
+ per_stage->time_ns / 1e6,
+ per_stage->time_ns / total * 100);
+
+ if (per_stage->active)
+ printf (", %4.1f%% active", per_stage->active * 100);
+
+ printf ("\n");
+
+ /* I'm not seeing a lot of value printing the rest of these
+ * performance counters by default yet. Use --verbose to get
+ * them for now. */
+ if (! verbose)
+ return;
+
+ printf ("[");
+ for (group_index = 0; group_index < info->num_groups; group_index++) {
+ group = &info->groups[group_index];
+ for (counter = 0; counter < group->num_counters; counter++) {
+
+ /* Don't print this counter value if it's a
+ * per-stage cycle counter, (which we have
+ * already accounted for). */
+ if (_is_shader_stage_counter (info, group_index, counter))
+ continue;
+
+ value = metric->counters[group_index][counter];
+ if (value == 0.0)
+ continue;
+ printf ("%s: %.2f ", group->counter_names[counter],
+ value / 1e6);
+ }
+ }
+ printf ("]\n");