+ 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 = ¤t_context;
+ unsigned char *p = (unsigned char *) result;
+
+ while (p < ((unsigned char *) result) + size)
+ {
+ GLuint group_id, counter_id, counter_type;
+ uint32_t value;
+ unsigned i;
+
+ CONSUME (group_id);
+ CONSUME (counter_id);
+
+ glGetPerfMonitorCounterInfoAMD (group_id, counter_id,
+ GL_COUNTER_TYPE_AMD,
+ &counter_type);
+
+ /* We assume that all peformance counters are made
+ * available as uint32 values. This code can easily be
+ * extended as needed. */
+ if (counter_type != GL_UNSIGNED_INT) {
+ fprintf (stderr, "Warning: Non-uint counter value. Ignoring remainder of results\n");
+ break;
+ }
+
+ CONSUME (value);
+
+ i = (group_id * ctx->metrics_info.max_counters_per_group +
+ counter_id);
+
+ assert (i < ctx->op_metrics[op].num_counters);
+
+ /* FIXME: While I'm still occasionally getting bogus
+ * numbers from the performance counters, I'm simply
+ * going to discard anything larger than half the
+ * range, (something that looks like a negative signed
+ * quantity).
+ */
+ if (((int32_t) value) < 0)
+ fprintf (stderr, ".");
+ else
+ ctx->op_metrics[op].counters[i] += value;
+ }
+}
+
+static void
+accumulate_program_time (metrics_op_t op, unsigned time_ns)
+{
+ op_metrics_t *metrics;
+
+ metrics = ctx_get_op_metrics (¤t_context, op);
+
+ metrics->time_ns += time_ns;