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_resource.h"
35 #include "freedreno_util.h"
36
37 /*
38 * Pipe Query interface:
39 */
40
41 static struct pipe_query *
fd_create_query(struct pipe_context * pctx,unsigned query_type,unsigned index)42 fd_create_query(struct pipe_context *pctx, unsigned query_type, unsigned index)
43 {
44 struct fd_context *ctx = fd_context(pctx);
45 struct fd_query *q = NULL;
46
47 if (ctx->create_query)
48 q = ctx->create_query(ctx, query_type, index);
49 if (!q)
50 q = fd_sw_create_query(ctx, query_type, index);
51
52 return (struct pipe_query *)q;
53 }
54
55 static void
fd_destroy_query(struct pipe_context * pctx,struct pipe_query * pq)56 fd_destroy_query(struct pipe_context *pctx, struct pipe_query *pq) in_dt
57 {
58 struct fd_query *q = fd_query(pq);
59 q->funcs->destroy_query(fd_context(pctx), q);
60 }
61
62 static bool
fd_begin_query(struct pipe_context * pctx,struct pipe_query * pq)63 fd_begin_query(struct pipe_context *pctx, struct pipe_query *pq) in_dt
64 {
65 struct fd_query *q = fd_query(pq);
66
67 q->funcs->begin_query(fd_context(pctx), q);
68
69 return true;
70 }
71
72 static bool
fd_end_query(struct pipe_context * pctx,struct pipe_query * pq)73 fd_end_query(struct pipe_context *pctx, struct pipe_query *pq) in_dt
74 {
75 struct fd_query *q = fd_query(pq);
76
77 /* there are a couple special cases, which don't have
78 * a matching ->begin_query():
79 */
80 if (skip_begin_query(q->type))
81 fd_begin_query(pctx, pq);
82
83 q->funcs->end_query(fd_context(pctx), q);
84
85 return true;
86 }
87
88 static bool
fd_get_query_result(struct pipe_context * pctx,struct pipe_query * pq,bool wait,union pipe_query_result * result)89 fd_get_query_result(struct pipe_context *pctx, struct pipe_query *pq, bool wait,
90 union pipe_query_result *result)
91 {
92 struct fd_query *q = fd_query(pq);
93
94 util_query_clear_result(result, q->type);
95
96 return q->funcs->get_query_result(fd_context(pctx), q, wait, result);
97 }
98
99 static void
fd_get_query_result_resource(struct pipe_context * pctx,struct pipe_query * pq,enum pipe_query_flags flags,enum pipe_query_value_type result_type,int index,struct pipe_resource * prsc,unsigned offset)100 fd_get_query_result_resource(struct pipe_context *pctx, struct pipe_query *pq,
101 enum pipe_query_flags flags,
102 enum pipe_query_value_type result_type,
103 int index, struct pipe_resource *prsc,
104 unsigned offset)
105 in_dt
106 {
107 struct fd_query *q = fd_query(pq);
108
109 q->funcs->get_query_result_resource(fd_context(pctx), q, flags, result_type,
110 index, fd_resource(prsc), offset);
111 }
112
113 static void
fd_render_condition(struct pipe_context * pctx,struct pipe_query * pq,bool condition,enum pipe_render_cond_flag mode)114 fd_render_condition(struct pipe_context *pctx, struct pipe_query *pq,
115 bool condition, enum pipe_render_cond_flag mode) in_dt
116 {
117 struct fd_context *ctx = fd_context(pctx);
118 ctx->cond_query = pq;
119 ctx->cond_cond = condition;
120 ctx->cond_mode = mode;
121 }
122
123 #define _Q(_name, _query_type, _type, _result_type) { \
124 .name = _name, .query_type = _query_type, \
125 .type = PIPE_DRIVER_QUERY_TYPE_##_type, \
126 .result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_##_result_type, \
127 .group_id = ~(unsigned)0, \
128 }
129
130 #define FQ(_name, _query_type, _type, _result_type) \
131 _Q(_name, FD_QUERY_##_query_type, _type, _result_type)
132
133 #define PQ(_name, _query_type, _type, _result_type) \
134 _Q(_name, PIPE_QUERY_##_query_type, _type, _result_type)
135
136 static const struct pipe_driver_query_info sw_query_list[] = {
137 FQ("draw-calls", DRAW_CALLS, UINT64, AVERAGE),
138 FQ("batches", BATCH_TOTAL, UINT64, AVERAGE),
139 FQ("batches-sysmem", BATCH_SYSMEM, UINT64, AVERAGE),
140 FQ("batches-gmem", BATCH_GMEM, UINT64, AVERAGE),
141 FQ("batches-nondraw", BATCH_NONDRAW, UINT64, AVERAGE),
142 FQ("restores", BATCH_RESTORE, UINT64, AVERAGE),
143 PQ("prims-emitted", PRIMITIVES_EMITTED, UINT64, AVERAGE),
144 FQ("staging", STAGING_UPLOADS, UINT64, AVERAGE),
145 FQ("shadow", SHADOW_UPLOADS, UINT64, AVERAGE),
146 FQ("vsregs", VS_REGS, FLOAT, AVERAGE),
147 FQ("fsregs", FS_REGS, FLOAT, AVERAGE),
148 };
149
150 static int
fd_get_driver_query_info(struct pipe_screen * pscreen,unsigned index,struct pipe_driver_query_info * info)151 fd_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
152 struct pipe_driver_query_info *info)
153 {
154 struct fd_screen *screen = fd_screen(pscreen);
155
156 if (!info)
157 return ARRAY_SIZE(sw_query_list) + screen->num_perfcntr_queries;
158
159 if (index >= ARRAY_SIZE(sw_query_list)) {
160 index -= ARRAY_SIZE(sw_query_list);
161 if (index >= screen->num_perfcntr_queries)
162 return 0;
163 *info = screen->perfcntr_queries[index];
164 return 1;
165 }
166
167 *info = sw_query_list[index];
168 return 1;
169 }
170
171 static int
fd_get_driver_query_group_info(struct pipe_screen * pscreen,unsigned index,struct pipe_driver_query_group_info * info)172 fd_get_driver_query_group_info(struct pipe_screen *pscreen, unsigned index,
173 struct pipe_driver_query_group_info *info)
174 {
175 struct fd_screen *screen = fd_screen(pscreen);
176
177 if (!info)
178 return screen->num_perfcntr_groups;
179
180 if (index >= screen->num_perfcntr_groups)
181 return 0;
182
183 const struct fd_perfcntr_group *g = &screen->perfcntr_groups[index];
184
185 info->name = g->name;
186 info->max_active_queries = g->num_counters;
187 info->num_queries = g->num_countables;
188
189 return 1;
190 }
191
192 static void
fd_set_active_query_state(struct pipe_context * pctx,bool enable)193 fd_set_active_query_state(struct pipe_context *pctx, bool enable) assert_dt
194 {
195 struct fd_context *ctx = fd_context(pctx);
196 ctx->active_queries = enable;
197 fd_context_dirty(ctx, FD_DIRTY_QUERY);
198 }
199
200 static enum pipe_driver_query_type
query_type(enum fd_perfcntr_type type)201 query_type(enum fd_perfcntr_type type)
202 {
203 #define ENUM(t) \
204 case FD_PERFCNTR_##t: \
205 return PIPE_DRIVER_QUERY_##t
206 switch (type) {
207 ENUM(TYPE_UINT64);
208 ENUM(TYPE_UINT);
209 ENUM(TYPE_FLOAT);
210 ENUM(TYPE_PERCENTAGE);
211 ENUM(TYPE_BYTES);
212 ENUM(TYPE_MICROSECONDS);
213 ENUM(TYPE_HZ);
214 ENUM(TYPE_DBM);
215 ENUM(TYPE_TEMPERATURE);
216 ENUM(TYPE_VOLTS);
217 ENUM(TYPE_AMPS);
218 ENUM(TYPE_WATTS);
219 default:
220 unreachable("bad type");
221 return 0;
222 }
223 }
224
225 static enum pipe_driver_query_result_type
query_result_type(enum fd_perfcntr_result_type type)226 query_result_type(enum fd_perfcntr_result_type type)
227 {
228 switch (type) {
229 ENUM(RESULT_TYPE_AVERAGE);
230 ENUM(RESULT_TYPE_CUMULATIVE);
231 default:
232 unreachable("bad type");
233 return 0;
234 }
235 }
236
237 static void
setup_perfcntr_query_info(struct fd_screen * screen)238 setup_perfcntr_query_info(struct fd_screen *screen)
239 {
240 unsigned num_queries = 0;
241
242 for (unsigned i = 0; i < screen->num_perfcntr_groups; i++)
243 num_queries += screen->perfcntr_groups[i].num_countables;
244
245 screen->perfcntr_queries =
246 calloc(num_queries, sizeof(screen->perfcntr_queries[0]));
247 screen->num_perfcntr_queries = num_queries;
248
249 unsigned idx = 0;
250 for (unsigned i = 0; i < screen->num_perfcntr_groups; i++) {
251 const struct fd_perfcntr_group *g = &screen->perfcntr_groups[i];
252 for (unsigned j = 0; j < g->num_countables; j++) {
253 struct pipe_driver_query_info *info = &screen->perfcntr_queries[idx];
254 const struct fd_perfcntr_countable *c = &g->countables[j];
255
256 info->name = c->name;
257 info->query_type = FD_QUERY_FIRST_PERFCNTR + idx;
258 info->type = query_type(c->query_type);
259 info->result_type = query_result_type(c->result_type);
260 info->group_id = i;
261 info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
262
263 idx++;
264 }
265 }
266 }
267
268 void
fd_query_screen_init(struct pipe_screen * pscreen)269 fd_query_screen_init(struct pipe_screen *pscreen)
270 {
271 pscreen->get_driver_query_info = fd_get_driver_query_info;
272 pscreen->get_driver_query_group_info = fd_get_driver_query_group_info;
273 setup_perfcntr_query_info(fd_screen(pscreen));
274 }
275
276 void
fd_query_context_init(struct pipe_context * pctx)277 fd_query_context_init(struct pipe_context *pctx)
278 {
279 pctx->create_query = fd_create_query;
280 pctx->destroy_query = fd_destroy_query;
281 pctx->begin_query = fd_begin_query;
282 pctx->end_query = fd_end_query;
283 pctx->get_query_result = fd_get_query_result;
284 pctx->get_query_result_resource = fd_get_query_result_resource;
285 pctx->set_active_query_state = fd_set_active_query_state;
286 pctx->render_condition = fd_render_condition;
287 }
288