1/*
2 * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Rob Clark <robclark@freedesktop.org>
25 */
26
27#include "pipe/p_state.h"
28#include "util/u_memory.h"
29
30#include "freedreno_context.h"
31#include "freedreno_query.h"
32#include "freedreno_query_hw.h"
33#include "freedreno_query_sw.h"
34#include "freedreno_util.h"
35
36/*
37 * Pipe Query interface:
38 */
39
40static struct pipe_query *
41fd_create_query(struct pipe_context *pctx, unsigned query_type, unsigned index)
42{
43   struct fd_context *ctx = fd_context(pctx);
44   struct fd_query *q = NULL;
45
46   if (ctx->create_query)
47      q = ctx->create_query(ctx, query_type, index);
48   if (!q)
49      q = fd_sw_create_query(ctx, query_type, index);
50
51   return (struct pipe_query *)q;
52}
53
54static void
55fd_destroy_query(struct pipe_context *pctx, struct pipe_query *pq) in_dt
56{
57   struct fd_query *q = fd_query(pq);
58   q->funcs->destroy_query(fd_context(pctx), q);
59}
60
61static bool
62fd_begin_query(struct pipe_context *pctx, struct pipe_query *pq) in_dt
63{
64   struct fd_query *q = fd_query(pq);
65
66   q->funcs->begin_query(fd_context(pctx), q);
67
68   return true;
69}
70
71static bool
72fd_end_query(struct pipe_context *pctx, struct pipe_query *pq) in_dt
73{
74   struct fd_query *q = fd_query(pq);
75
76   /* there are a couple special cases, which don't have
77    * a matching ->begin_query():
78    */
79   if (skip_begin_query(q->type))
80      fd_begin_query(pctx, pq);
81
82   q->funcs->end_query(fd_context(pctx), q);
83
84   return true;
85}
86
87static bool
88fd_get_query_result(struct pipe_context *pctx, struct pipe_query *pq, bool wait,
89                    union pipe_query_result *result)
90{
91   struct fd_query *q = fd_query(pq);
92
93   util_query_clear_result(result, q->type);
94
95   return q->funcs->get_query_result(fd_context(pctx), q, wait, result);
96}
97
98static void
99fd_render_condition(struct pipe_context *pctx, struct pipe_query *pq,
100                    bool condition, enum pipe_render_cond_flag mode) in_dt
101{
102   struct fd_context *ctx = fd_context(pctx);
103   ctx->cond_query = pq;
104   ctx->cond_cond = condition;
105   ctx->cond_mode = mode;
106}
107
108#define _Q(_name, _query_type, _type, _result_type) {                          \
109      .name = _name, .query_type = _query_type,                                \
110      .type = PIPE_DRIVER_QUERY_TYPE_##_type,                                  \
111      .result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_##_result_type,             \
112      .group_id = ~(unsigned)0,                                                \
113   }
114
115#define FQ(_name, _query_type, _type, _result_type)                            \
116   _Q(_name, FD_QUERY_##_query_type, _type, _result_type)
117
118#define PQ(_name, _query_type, _type, _result_type)                            \
119   _Q(_name, PIPE_QUERY_##_query_type, _type, _result_type)
120
121static const struct pipe_driver_query_info sw_query_list[] = {
122   FQ("draw-calls", DRAW_CALLS, UINT64, AVERAGE),
123   FQ("batches", BATCH_TOTAL, UINT64, AVERAGE),
124   FQ("batches-sysmem", BATCH_SYSMEM, UINT64, AVERAGE),
125   FQ("batches-gmem", BATCH_GMEM, UINT64, AVERAGE),
126   FQ("batches-nondraw", BATCH_NONDRAW, UINT64, AVERAGE),
127   FQ("restores", BATCH_RESTORE, UINT64, AVERAGE),
128   PQ("prims-emitted", PRIMITIVES_EMITTED, UINT64, AVERAGE),
129   FQ("staging", STAGING_UPLOADS, UINT64, AVERAGE),
130   FQ("shadow", SHADOW_UPLOADS, UINT64, AVERAGE),
131   FQ("vsregs", VS_REGS, FLOAT, AVERAGE),
132   FQ("fsregs", FS_REGS, FLOAT, AVERAGE),
133};
134
135static int
136fd_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
137                         struct pipe_driver_query_info *info)
138{
139   struct fd_screen *screen = fd_screen(pscreen);
140
141   if (!info)
142      return ARRAY_SIZE(sw_query_list) + screen->num_perfcntr_queries;
143
144   if (index >= ARRAY_SIZE(sw_query_list)) {
145      index -= ARRAY_SIZE(sw_query_list);
146      if (index >= screen->num_perfcntr_queries)
147         return 0;
148      *info = screen->perfcntr_queries[index];
149      return 1;
150   }
151
152   *info = sw_query_list[index];
153   return 1;
154}
155
156static int
157fd_get_driver_query_group_info(struct pipe_screen *pscreen, unsigned index,
158                               struct pipe_driver_query_group_info *info)
159{
160   struct fd_screen *screen = fd_screen(pscreen);
161
162   if (!info)
163      return screen->num_perfcntr_groups;
164
165   if (index >= screen->num_perfcntr_groups)
166      return 0;
167
168   const struct fd_perfcntr_group *g = &screen->perfcntr_groups[index];
169
170   info->name = g->name;
171   info->max_active_queries = g->num_counters;
172   info->num_queries = g->num_countables;
173
174   return 1;
175}
176
177static void
178fd_set_active_query_state(struct pipe_context *pctx, bool enable) assert_dt
179{
180   struct fd_context *ctx = fd_context(pctx);
181   ctx->active_queries = enable;
182   ctx->update_active_queries = true;
183}
184
185static enum pipe_driver_query_type
186query_type(enum fd_perfcntr_type type)
187{
188#define ENUM(t)                                                                \
189   case FD_PERFCNTR_##t:                                                       \
190      return PIPE_DRIVER_QUERY_##t
191   switch (type) {
192      ENUM(TYPE_UINT64);
193      ENUM(TYPE_UINT);
194      ENUM(TYPE_FLOAT);
195      ENUM(TYPE_PERCENTAGE);
196      ENUM(TYPE_BYTES);
197      ENUM(TYPE_MICROSECONDS);
198      ENUM(TYPE_HZ);
199      ENUM(TYPE_DBM);
200      ENUM(TYPE_TEMPERATURE);
201      ENUM(TYPE_VOLTS);
202      ENUM(TYPE_AMPS);
203      ENUM(TYPE_WATTS);
204   default:
205      unreachable("bad type");
206      return 0;
207   }
208}
209
210static enum pipe_driver_query_result_type
211query_result_type(enum fd_perfcntr_result_type type)
212{
213   switch (type) {
214      ENUM(RESULT_TYPE_AVERAGE);
215      ENUM(RESULT_TYPE_CUMULATIVE);
216   default:
217      unreachable("bad type");
218      return 0;
219   }
220}
221
222static void
223setup_perfcntr_query_info(struct fd_screen *screen)
224{
225   unsigned num_queries = 0;
226
227   for (unsigned i = 0; i < screen->num_perfcntr_groups; i++)
228      num_queries += screen->perfcntr_groups[i].num_countables;
229
230   screen->perfcntr_queries =
231      calloc(num_queries, sizeof(screen->perfcntr_queries[0]));
232   screen->num_perfcntr_queries = num_queries;
233
234   unsigned idx = 0;
235   for (unsigned i = 0; i < screen->num_perfcntr_groups; i++) {
236      const struct fd_perfcntr_group *g = &screen->perfcntr_groups[i];
237      for (unsigned j = 0; j < g->num_countables; j++) {
238         struct pipe_driver_query_info *info = &screen->perfcntr_queries[idx];
239         const struct fd_perfcntr_countable *c = &g->countables[j];
240
241         info->name = c->name;
242         info->query_type = FD_QUERY_FIRST_PERFCNTR + idx;
243         info->type = query_type(c->query_type);
244         info->result_type = query_result_type(c->result_type);
245         info->group_id = i;
246         info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
247
248         idx++;
249      }
250   }
251}
252
253void
254fd_query_screen_init(struct pipe_screen *pscreen)
255{
256   pscreen->get_driver_query_info = fd_get_driver_query_info;
257   pscreen->get_driver_query_group_info = fd_get_driver_query_group_info;
258   setup_perfcntr_query_info(fd_screen(pscreen));
259}
260
261void
262fd_query_context_init(struct pipe_context *pctx)
263{
264   pctx->create_query = fd_create_query;
265   pctx->destroy_query = fd_destroy_query;
266   pctx->begin_query = fd_begin_query;
267   pctx->end_query = fd_end_query;
268   pctx->get_query_result = fd_get_query_result;
269   pctx->set_active_query_state = fd_set_active_query_state;
270   pctx->render_condition = fd_render_condition;
271}
272