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
40 static struct pipe_query *
fd_create_query(struct pipe_context * pctx,unsigned query_type,unsigned index)41 fd_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
54 static void
fd_destroy_query(struct pipe_context * pctx,struct pipe_query * pq)55 fd_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
61 static bool
fd_begin_query(struct pipe_context * pctx,struct pipe_query * pq)62 fd_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
71 static bool
fd_end_query(struct pipe_context * pctx,struct pipe_query * pq)72 fd_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
87 static bool
fd_get_query_result(struct pipe_context * pctx,struct pipe_query * pq,bool wait,union pipe_query_result * result)88 fd_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
98 static void
fd_render_condition(struct pipe_context * pctx,struct pipe_query * pq,bool condition,enum pipe_render_cond_flag mode)99 fd_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
121 static 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
135 static int
fd_get_driver_query_info(struct pipe_screen * pscreen,unsigned index,struct pipe_driver_query_info * info)136 fd_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
156 static int
fd_get_driver_query_group_info(struct pipe_screen * pscreen,unsigned index,struct pipe_driver_query_group_info * info)157 fd_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
177 static void
fd_set_active_query_state(struct pipe_context * pctx,bool enable)178 fd_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
185 static enum pipe_driver_query_type
query_type(enum fd_perfcntr_type type)186 query_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
210 static enum pipe_driver_query_result_type
query_result_type(enum fd_perfcntr_result_type type)211 query_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
222 static void
setup_perfcntr_query_info(struct fd_screen * screen)223 setup_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
253 void
fd_query_screen_init(struct pipe_screen * pscreen)254 fd_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
261 void
fd_query_context_init(struct pipe_context * pctx)262 fd_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