From 824789d9fbe591782b55a8d347e588735bab0040 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Mon, 4 Nov 2013 15:44:23 -0800 Subject: [PATCH] Fix fips to work even without the GL_AMD_performance_monitor extension. Even without the extension, we can still do timer queries and print the time spent in each operation. So detect that the extension is available, and then use that information to avoid calling into any functions that are only made available with that extension. The first report generated with a context that does not have the extension will include a warning that the extension was not available. --- context.c | 29 ++++++++++++++++- metrics-info.c | 15 ++++++++- metrics-info.h | 9 +++++- metrics.c | 85 ++++++++++++++++++++++++++++++++++---------------- 4 files changed, 108 insertions(+), 30 deletions(-) diff --git a/context.c b/context.c index 133c37c..3c58a60 100644 --- a/context.c +++ b/context.c @@ -28,12 +28,18 @@ typedef struct context /* Pointer to the system's context ID, (such as a GLXContext) */ void *system_id; + /* Does this context have the AMD_performance_monitor extension? */ + bool have_perfmon; + metrics_info_t metrics_info; metrics_t *metrics; } context_t; context_t *current_context; +static bool +check_extension (const char *extension); + static context_t * context_create (fips_api_t api, void *system_context_id) { @@ -45,7 +51,9 @@ context_create (fips_api_t api, void *system_context_id) fips_dispatch_init (api); - metrics_info_init (&ctx->metrics_info); + ctx->have_perfmon = check_extension ("GL_AMD_performance_monitor"); + + metrics_info_init (&ctx->metrics_info, ctx->have_perfmon); ctx->metrics = metrics_create (&ctx->metrics_info); return ctx; @@ -115,3 +123,22 @@ context_end_frame (void) { return metrics_end_frame (current_context->metrics); } + +/* Is the given extension available? */ +static bool +check_extension (const char *extension) +{ + int i, num_extensions; + const char *available; + + glGetIntegerv (GL_NUM_EXTENSIONS, &num_extensions); + + for (i = 0; i < num_extensions; i++) { + available = (char *) glGetStringi (GL_EXTENSIONS, i); + if (strcmp (extension, available) == 0) { + return true; + } + } + + return false; +} diff --git a/metrics-info.c b/metrics-info.c index 860e435..4136467 100644 --- a/metrics-info.c +++ b/metrics-info.c @@ -156,11 +156,24 @@ _add_shader_stage (metrics_info_t *info, const char *name, } void -metrics_info_init (metrics_info_t *info) +metrics_info_init (metrics_info_t *info, bool have_perfmon) { unsigned i, j; GLuint *group_ids; + info->have_perfmon = have_perfmon; + info->printed_missing_perfmon_warning = false; + + if (! have_perfmon) { + info->groups = NULL; + info->num_groups = 0; + info->num_shader_stages = 0; + info->stages = NULL; + info->initialized = 1; + + return; + } + glGetPerfMonitorGroupsAMD ((int *) &info->num_groups, 0, NULL); group_ids = xmalloc (info->num_groups * sizeof (GLuint)); diff --git a/metrics-info.h b/metrics-info.h index 1340c83..f03352e 100644 --- a/metrics-info.h +++ b/metrics-info.h @@ -54,6 +54,9 @@ typedef struct metrics_info { int initialized; + bool have_perfmon; + bool printed_missing_perfmon_warning; + unsigned num_groups; metrics_group_info_t *groups; @@ -67,9 +70,13 @@ typedef struct metrics_info * This queries the names and ranges for all available performance counters. * * This should be called before any other metrics functions. + * + * The Boolean have_perfmon must be set to correctly indicate whether + * the current OpenGL context has the AMD_performance_monitor + * extension. */ void -metrics_info_init (metrics_info_t *info); +metrics_info_init (metrics_info_t *info, bool have_perfmon); /* Finalize metrics info state. * diff --git a/metrics.c b/metrics.c index 004c339..79aeb6d 100644 --- a/metrics.c +++ b/metrics.c @@ -153,22 +153,26 @@ metrics_fini (metrics_t *metrics) metrics->timer_head = NULL; metrics->timer_tail = NULL; - if (metrics->monitor_begun_id) { - glEndPerfMonitorAMD (metrics->monitor_begun_id); - glDeletePerfMonitorsAMD (1, &metrics->monitor_begun_id); - metrics->monitor_begun_id = 0; - } + if (metrics->info->have_perfmon) { + + if (metrics->monitor_begun_id) { + glEndPerfMonitorAMD (metrics->monitor_begun_id); + glDeletePerfMonitorsAMD (1, &metrics->monitor_begun_id); + metrics->monitor_begun_id = 0; + } + + for (monitor = metrics->monitor_head; + monitor; + monitor = monitor_next) + { + glDeletePerfMonitorsAMD (1, &monitor->id); + monitor_next = monitor->next; + free (monitor); + } + metrics->monitor_head = NULL; + metrics->monitor_tail = NULL; - for (monitor = metrics->monitor_head; - monitor; - monitor = monitor_next) - { - glDeletePerfMonitorsAMD (1, &monitor->id); - monitor_next = monitor->next; - free (monitor); } - metrics->monitor_head = NULL; - metrics->monitor_tail = NULL; metrics->monitors_in_flight = 0; } @@ -231,9 +235,18 @@ metrics_counter_start (metrics_t *metrics) { unsigned i; - /* Initialize the timer_query and monitor objects */ + /* Initialize the timer_query object. */ glGenQueries (1, &metrics->timer_begun_id); + /* Most everything else in this function is + * performance-monitor related. If we don't have that + * extension, just start the timer query and be done. */ + if (! metrics->info->have_perfmon) { + glBeginQuery (GL_TIME_ELAPSED, metrics->timer_begun_id); + return; + } + + /* Initialize the performance-monitor object */ glGenPerfMonitorsAMD (1, &metrics->monitor_begun_id); for (i = 0; i < metrics->info->num_groups; i++) @@ -273,7 +286,9 @@ metrics_counter_stop (metrics_t *metrics) /* Stop the current timer and monitor. */ glEndQuery (GL_TIME_ELAPSED); - glEndPerfMonitorAMD (metrics->monitor_begun_id); + + if (metrics->info->have_perfmon) + glEndPerfMonitorAMD (metrics->monitor_begun_id); /* Add these IDs to our lists of outstanding queries and * monitors so the results can be collected later. */ @@ -291,19 +306,21 @@ metrics_counter_stop (metrics_t *metrics) metrics->timer_head = timer; } - /* Create a new performance-monitor query */ - monitor = xmalloc (sizeof (monitor_t)); + if (metrics->info->have_perfmon) { + /* Create a new performance-monitor query */ + monitor = xmalloc (sizeof (monitor_t)); - monitor->op = metrics->op; - monitor->id = metrics->monitor_begun_id; - monitor->next = NULL; + monitor->op = metrics->op; + monitor->id = metrics->monitor_begun_id; + monitor->next = NULL; - if (metrics->monitor_tail) { - metrics->monitor_tail->next = monitor; - metrics->monitor_tail = monitor; - } else { - metrics->monitor_tail = monitor; - metrics->monitor_head = monitor; + if (metrics->monitor_tail) { + metrics->monitor_tail->next = monitor; + metrics->monitor_tail = monitor; + } else { + metrics->monitor_tail = monitor; + metrics->monitor_head = monitor; + } } metrics->monitors_in_flight++; @@ -576,6 +593,17 @@ print_program_metrics (metrics_t *metrics) unsigned group_index, counter_index; unsigned i, j, num_sorted; + if (! info->have_perfmon && + ! info->printed_missing_perfmon_warning) + { + fprintf (stderr, + "Warning: The GL_AMD_performance_monitor extensions is not available.\n" + " Some fips features, (such as per-shader-stage timings),\n" + " will not be available.\n"); + + info->printed_missing_perfmon_warning = true; + } + /* Make a sorted list of the per-stage operations by time * used, and figure out the total so we can print percentages. */ @@ -700,6 +728,9 @@ metrics_collect_available (metrics_t *metrics) 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; -- 2.43.0