-/* -*- mode: C; c-file-style: "k&r"; ttxab-width 4; indent-tabs-mode: t; -*- */
-
/*
- * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
+ * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
*/
#include "pipe/p_state.h"
-#include "util/u_string.h"
#include "util/u_memory.h"
-#include "util/u_inlines.h"
-#include "os/os_time.h"
#include "freedreno_query.h"
+#include "freedreno_query_sw.h"
+#include "freedreno_query_hw.h"
#include "freedreno_context.h"
#include "freedreno_util.h"
-#define FD_QUERY_DRAW_CALLS (PIPE_QUERY_DRIVER_SPECIFIC + 0)
-#define FD_QUERY_BATCH_TOTAL (PIPE_QUERY_DRIVER_SPECIFIC + 1) /* total # of batches (submits) */
-#define FD_QUERY_BATCH_SYSMEM (PIPE_QUERY_DRIVER_SPECIFIC + 2) /* batches using system memory (GMEM bypass) */
-#define FD_QUERY_BATCH_GMEM (PIPE_QUERY_DRIVER_SPECIFIC + 3) /* batches using GMEM */
-#define FD_QUERY_BATCH_RESTORE (PIPE_QUERY_DRIVER_SPECIFIC + 4) /* batches requiring GMEM restore */
-
-/* Currently just simple cpu query's supported.. probably need
- * to refactor this a bit when I'm eventually ready to add gpu
- * queries:
+/*
+ * Pipe Query interface:
*/
-struct fd_query {
- int type;
- /* storage for the collected data */
- union pipe_query_result data;
- bool active;
- uint64_t begin_value, end_value;
- uint64_t begin_time, end_time;
-};
-
-static inline struct fd_query *
-fd_query(struct pipe_query *pq)
-{
- return (struct fd_query *)pq;
-}
static struct pipe_query *
-fd_create_query(struct pipe_context *pctx, unsigned query_type)
+fd_create_query(struct pipe_context *pctx, unsigned query_type, unsigned index)
{
- struct fd_query *q;
-
- switch (query_type) {
- case PIPE_QUERY_PRIMITIVES_GENERATED:
- case PIPE_QUERY_PRIMITIVES_EMITTED:
- case FD_QUERY_DRAW_CALLS:
- case FD_QUERY_BATCH_TOTAL:
- case FD_QUERY_BATCH_SYSMEM:
- case FD_QUERY_BATCH_GMEM:
- case FD_QUERY_BATCH_RESTORE:
- break;
- default:
- return NULL;
- }
+ struct fd_context *ctx = fd_context(pctx);
+ struct fd_query *q = NULL;
- q = CALLOC_STRUCT(fd_query);
+ if (ctx->create_query)
+ q = ctx->create_query(ctx, query_type, index);
if (!q)
- return NULL;
-
- q->type = query_type;
+ q = fd_sw_create_query(ctx, query_type, index);
return (struct pipe_query *) q;
}
fd_destroy_query(struct pipe_context *pctx, struct pipe_query *pq)
{
struct fd_query *q = fd_query(pq);
- free(q);
-}
-
-static uint64_t
-read_counter(struct pipe_context *pctx, int type)
-{
- struct fd_context *ctx = fd_context(pctx);
- switch (type) {
- case PIPE_QUERY_PRIMITIVES_GENERATED:
- /* for now same thing as _PRIMITIVES_EMITTED */
- case PIPE_QUERY_PRIMITIVES_EMITTED:
- return ctx->stats.prims_emitted;
- case FD_QUERY_DRAW_CALLS:
- return ctx->stats.draw_calls;
- case FD_QUERY_BATCH_TOTAL:
- return ctx->stats.batch_total;
- case FD_QUERY_BATCH_SYSMEM:
- return ctx->stats.batch_sysmem;
- case FD_QUERY_BATCH_GMEM:
- return ctx->stats.batch_gmem;
- case FD_QUERY_BATCH_RESTORE:
- return ctx->stats.batch_restore;
- }
- return 0;
+ q->funcs->destroy_query(fd_context(pctx), q);
}
static bool
-is_rate_query(struct fd_query *q)
-{
- switch (q->type) {
- case FD_QUERY_BATCH_TOTAL:
- case FD_QUERY_BATCH_SYSMEM:
- case FD_QUERY_BATCH_GMEM:
- case FD_QUERY_BATCH_RESTORE:
- return true;
- default:
- return false;
- }
-}
-
-static void
fd_begin_query(struct pipe_context *pctx, struct pipe_query *pq)
{
struct fd_query *q = fd_query(pq);
- q->active = true;
- q->begin_value = read_counter(pctx, q->type);
- if (is_rate_query(q))
- q->begin_time = os_time_get();
+ bool ret;
+
+ if (q->active)
+ return false;
+
+ ret = q->funcs->begin_query(fd_context(pctx), q);
+ q->active = ret;
+
+ return ret;
}
-static void
+static bool
fd_end_query(struct pipe_context *pctx, struct pipe_query *pq)
{
struct fd_query *q = fd_query(pq);
+
+ /* there are a couple special cases, which don't have
+ * a matching ->begin_query():
+ */
+ if (skip_begin_query(q->type) && !q->active)
+ fd_begin_query(pctx, pq);
+
+ if (!q->active)
+ return false;
+
+ q->funcs->end_query(fd_context(pctx), q);
q->active = false;
- q->end_value = read_counter(pctx, q->type);
- if (is_rate_query(q))
- q->end_time = os_time_get();
+
+ return true;
}
-static boolean
+static bool
fd_get_query_result(struct pipe_context *pctx, struct pipe_query *pq,
- boolean wait, union pipe_query_result *result)
+ bool wait, union pipe_query_result *result)
{
struct fd_query *q = fd_query(pq);
util_query_clear_result(result, q->type);
- result->u64 = q->end_value - q->begin_value;
+ return q->funcs->get_query_result(fd_context(pctx), q, wait, result);
+}
- if (is_rate_query(q)) {
- double fps = (result->u64 * 1000000) /
- (double)(q->end_time - q->begin_time);
- result->u64 = (uint64_t)fps;
- }
+static void
+fd_render_condition(struct pipe_context *pctx, struct pipe_query *pq,
+ bool condition, enum pipe_render_cond_flag mode)
+{
+ struct fd_context *ctx = fd_context(pctx);
+ ctx->cond_query = pq;
+ ctx->cond_cond = condition;
+ ctx->cond_mode = mode;
+}
- return true;
+#define _Q(_name, _query_type, _type, _result_type) { \
+ .name = _name, \
+ .query_type = _query_type, \
+ .type = PIPE_DRIVER_QUERY_TYPE_ ## _type, \
+ .result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_ ## _result_type, \
+ .group_id = ~(unsigned)0, \
}
+#define FQ(_name, _query_type, _type, _result_type) \
+ _Q(_name, FD_QUERY_ ## _query_type, _type, _result_type)
+
+#define PQ(_name, _query_type, _type, _result_type) \
+ _Q(_name, PIPE_QUERY_ ## _query_type, _type, _result_type)
+
+static const struct pipe_driver_query_info sw_query_list[] = {
+ FQ("draw-calls", DRAW_CALLS, UINT64, AVERAGE),
+ FQ("batches", BATCH_TOTAL, UINT64, AVERAGE),
+ FQ("batches-sysmem", BATCH_SYSMEM, UINT64, AVERAGE),
+ FQ("batches-gmem", BATCH_GMEM, UINT64, AVERAGE),
+ FQ("batches-nondraw", BATCH_NONDRAW, UINT64, AVERAGE),
+ FQ("restores", BATCH_RESTORE, UINT64, AVERAGE),
+ PQ("prims-emitted", PRIMITIVES_EMITTED, UINT64, AVERAGE),
+ FQ("staging", STAGING_UPLOADS, UINT64, AVERAGE),
+ FQ("shadow", SHADOW_UPLOADS, UINT64, AVERAGE),
+ FQ("vsregs", VS_REGS, FLOAT, AVERAGE),
+ FQ("fsregs", FS_REGS, FLOAT, AVERAGE),
+};
+
static int
fd_get_driver_query_info(struct pipe_screen *pscreen,
unsigned index, struct pipe_driver_query_info *info)
{
- struct pipe_driver_query_info list[] = {
- {"draw-calls", FD_QUERY_DRAW_CALLS, 0},
- {"batches", FD_QUERY_BATCH_TOTAL, 0},
- {"batches-sysmem", FD_QUERY_BATCH_SYSMEM, 0},
- {"batches-gmem", FD_QUERY_BATCH_GMEM, 0},
- {"restores", FD_QUERY_BATCH_RESTORE, 0},
- {"prims-emitted", PIPE_QUERY_PRIMITIVES_EMITTED, 0},
- };
+ struct fd_screen *screen = fd_screen(pscreen);
+
+ if (!info)
+ return ARRAY_SIZE(sw_query_list) + screen->num_perfcntr_queries;
+
+ if (index >= ARRAY_SIZE(sw_query_list)) {
+ index -= ARRAY_SIZE(sw_query_list);
+ if (index >= screen->num_perfcntr_queries)
+ return 0;
+ *info = screen->perfcntr_queries[index];
+ return 1;
+ }
+
+ *info = sw_query_list[index];
+ return 1;
+}
+
+static int
+fd_get_driver_query_group_info(struct pipe_screen *pscreen, unsigned index,
+ struct pipe_driver_query_group_info *info)
+{
+ struct fd_screen *screen = fd_screen(pscreen);
if (!info)
- return ARRAY_SIZE(list);
+ return screen->num_perfcntr_groups;
- if (index >= ARRAY_SIZE(list))
+ if (index >= screen->num_perfcntr_groups)
return 0;
- *info = list[index];
+ const struct fd_perfcntr_group *g = &screen->perfcntr_groups[index];
+
+ info->name = g->name;
+ info->max_active_queries = g->num_counters;
+ info->num_queries = g->num_countables;
+
return 1;
}
+static void
+fd_set_active_query_state(struct pipe_context *pipe, bool enable)
+{
+}
+
+static void
+setup_perfcntr_query_info(struct fd_screen *screen)
+{
+ unsigned num_queries = 0;
+
+ for (unsigned i = 0; i < screen->num_perfcntr_groups; i++)
+ num_queries += screen->perfcntr_groups[i].num_countables;
+
+ screen->perfcntr_queries =
+ calloc(num_queries, sizeof(screen->perfcntr_queries[0]));
+ screen->num_perfcntr_queries = num_queries;
+
+ unsigned idx = 0;
+ for (unsigned i = 0; i < screen->num_perfcntr_groups; i++) {
+ const struct fd_perfcntr_group *g = &screen->perfcntr_groups[i];
+ for (unsigned j = 0; j < g->num_countables; j++) {
+ struct pipe_driver_query_info *info =
+ &screen->perfcntr_queries[idx];
+ const struct fd_perfcntr_countable *c =
+ &g->countables[j];
+
+ info->name = c->name;
+ info->query_type = FD_QUERY_FIRST_PERFCNTR + idx;
+ info->type = c->query_type;
+ info->result_type = c->result_type;
+ info->group_id = i;
+ info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
+
+ idx++;
+ }
+ }
+}
+
void
fd_query_screen_init(struct pipe_screen *pscreen)
{
pscreen->get_driver_query_info = fd_get_driver_query_info;
+ pscreen->get_driver_query_group_info = fd_get_driver_query_group_info;
+ setup_perfcntr_query_info(fd_screen(pscreen));
}
void
pctx->begin_query = fd_begin_query;
pctx->end_query = fd_end_query;
pctx->get_query_result = fd_get_query_result;
+ pctx->set_active_query_state = fd_set_active_query_state;
+ pctx->render_condition = fd_render_condition;
}