+ glGetQueryObjectuiv (timer->id,
+ GL_QUERY_RESULT, &elapsed);
+
+ accumulate_program_time (metrics, timer->op, elapsed);
+
+ metrics->timer_head = timer->next;
+ if (metrics->timer_head == NULL)
+ metrics->timer_tail = NULL;
+
+ glDeleteQueries (1, &timer->id);
+
+ free (timer);
+ timer = metrics->timer_head;
+ }
+
+ if (! metrics->info->have_perfmon)
+ return;
+
+ /* And similarly for all performance monitors that are ready. */
+ monitor_t *monitor = metrics->monitor_head;
+
+ while (monitor) {
+ GLuint available, result_size, *result;
+ GLint bytes_written;
+
+ glGetPerfMonitorCounterDataAMD (monitor->id,
+ GL_PERFMON_RESULT_AVAILABLE_AMD,
+ sizeof (available), &available,
+ NULL);
+ if (! available)
+ break;
+
+ glGetPerfMonitorCounterDataAMD (monitor->id,
+ GL_PERFMON_RESULT_SIZE_AMD,
+ sizeof (result_size),
+ &result_size, NULL);
+
+ result = xmalloc (result_size);
+
+ glGetPerfMonitorCounterDataAMD (monitor->id,
+ GL_PERFMON_RESULT_AMD,
+ result_size, result,
+ &bytes_written);
+
+ accumulate_program_metrics (metrics, monitor->op, result, result_size);
+
+ free (result);
+
+ metrics->monitor_head = monitor->next;
+ if (metrics->monitor_head == NULL)
+ metrics->monitor_tail = NULL;
+
+ glDeletePerfMonitorsAMD (1, &monitor->id);
+
+ free (monitor);
+
+ metrics->monitors_in_flight--;
+
+ monitor = metrics->monitor_head;
+ }
+}
+
+/* Subtract timespec values: Return (a - b) in seconds as a double. */
+#define SUBTRACT_TIMESPEC(a, b) (double) (a.tv_sec - b.tv_sec + \
+ (a.tv_nsec - b.tv_nsec) / 1e9)
+
+void
+metrics_end_frame_pre_swap (metrics_t *metrics)
+{
+ GLuint64 swap_end_timestamp, frame_time_ns, latency_ns;
+ double cpu_time;
+
+ /* Don't leave any counters running over the end_frame work we
+ * do here. The counters will be started again at the end of
+ * metrics_end_frame_post_swap. */
+
+ metrics_counter_stop (metrics);
+
+ /* Now that an entire frame's worth of content has gone by, we
+ * can be sure that the timer quiery for the previous frame's
+ * swap is available.
+ *
+ * Note: The only case in which this query isn't immediately
+ * available would be if there was effectively nothing in this
+ * frame. In that case, triggering a block on this query
+ * result is not a concern (since an empty frame is not
+ * interesting, and all of our counters are stopped anyway).
+ *
+ * Accepting this one block is much better than adding a
+ * linked list for these results that would reaslisticly never
+ * have more than one entry anyway.
+ */
+
+ glGetQueryObjectui64v (metrics->swap_end_timestamp_id,
+ GL_QUERY_RESULT, &swap_end_timestamp);
+
+ if (metrics->first_frame) {
+ /* Print header */
+ printf ("# frame: Frame_Number Frame_Time_milliseconds Frame_latency_milliseconds CPU_load GPU_load\n");
+
+ metrics->first_frame = false;
+ } else {
+ /* Subtract previous frame's times to get frame times. */
+ frame_time_ns = subtract_timestamp (swap_end_timestamp,
+ metrics->previous_swap_end_timestamp);
+
+ latency_ns = subtract_timestamp (swap_end_timestamp,
+ metrics->swap_begin_timestamp);
+
+ cpu_time = SUBTRACT_TIMESPEC (metrics->cpu_time_ts,
+ metrics->previous_cpu_time_ts);
+
+ /* We've waited one frame to ensure we have a timestamp
+ * result. So the time we've actually measured here is
+ * for the previous frame. */
+ printf ("frame: %d %g %g %g %g\n",
+ frames - 1,
+ (double) frame_time_ns / 1e6,
+ (double) latency_ns / 1e6,
+ cpu_time / (frame_time_ns / 1e9),
+ 0.0);
+ }
+
+ metrics->previous_swap_end_timestamp = swap_end_timestamp;
+ metrics->previous_cpu_time_ts = metrics->cpu_time_ts;