+ return metrics->op;
+}
+
+static void
+op_metrics_init (metrics_info_t *info, op_metrics_t *metrics, metrics_op_t op)
+{
+ unsigned i, j;
+
+ metrics->op = op;
+ metrics->time_ns = 0.0;
+
+ metrics->counters = xmalloc (sizeof(double *) * info->num_groups);
+
+ for (i = 0; i < info->num_groups; i++) {
+ metrics->counters[i] = xmalloc (sizeof (double) *
+ info->groups[i].num_counters);
+ for (j = 0; j < info->groups[i].num_counters; j++)
+ metrics->counters[i][j] = 0.0;
+ }
+}
+
+static op_metrics_t *
+_get_op_metrics (metrics_t *metrics, metrics_op_t op)
+{
+ unsigned i;
+
+ if (op >= metrics->num_op_metrics)
+ {
+ metrics->op_metrics = realloc (metrics->op_metrics,
+ (op + 1) * sizeof (op_metrics_t));
+ for (i = metrics->num_op_metrics; i < op + 1; i++)
+ op_metrics_init (metrics->info, &metrics->op_metrics[i], i);
+
+ metrics->num_op_metrics = op + 1;
+ }
+
+ return &metrics->op_metrics[op];
+}
+
+static void
+accumulate_program_metrics (metrics_t *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);
+
+ metrics_info_t *info = metrics->info;
+ op_metrics_t *op_metrics = _get_op_metrics (metrics, 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 = 0.0;
+ 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;
+ }
+
+ op_metrics->counters[group_index][counter_index] += value;
+ }