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_query.h"
31#include "freedreno_query_sw.h"
32#include "freedreno_query_hw.h"
33#include "freedreno_context.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;
45
46	q = fd_sw_create_query(ctx, query_type);
47	if (!q && ctx->create_query)
48		q = ctx->create_query(ctx, query_type);
49
50	return (struct pipe_query *) q;
51}
52
53static void
54fd_destroy_query(struct pipe_context *pctx, struct pipe_query *pq)
55{
56	struct fd_query *q = fd_query(pq);
57	q->funcs->destroy_query(fd_context(pctx), q);
58}
59
60static boolean
61fd_begin_query(struct pipe_context *pctx, struct pipe_query *pq)
62{
63	struct fd_query *q = fd_query(pq);
64	boolean ret;
65
66	if (q->active)
67		return false;
68
69	ret = q->funcs->begin_query(fd_context(pctx), q);
70	q->active = ret;
71
72	return ret;
73}
74
75static bool
76fd_end_query(struct pipe_context *pctx, struct pipe_query *pq)
77{
78	struct fd_query *q = fd_query(pq);
79
80	/* there are a couple special cases, which don't have
81	 * a matching ->begin_query():
82	 */
83	if (skip_begin_query(q->type) && !q->active)
84		fd_begin_query(pctx, pq);
85
86	if (!q->active)
87		return false;
88
89	q->funcs->end_query(fd_context(pctx), q);
90	q->active = false;
91
92	return true;
93}
94
95static boolean
96fd_get_query_result(struct pipe_context *pctx, struct pipe_query *pq,
97		boolean wait, union pipe_query_result *result)
98{
99	struct fd_query *q = fd_query(pq);
100
101	if (q->active)
102		return false;
103
104	util_query_clear_result(result, q->type);
105
106	return q->funcs->get_query_result(fd_context(pctx), q, wait, result);
107}
108
109static void
110fd_render_condition(struct pipe_context *pctx, struct pipe_query *pq,
111					boolean condition, enum pipe_render_cond_flag mode)
112{
113	struct fd_context *ctx = fd_context(pctx);
114	ctx->cond_query = pq;
115	ctx->cond_cond = condition;
116	ctx->cond_mode = mode;
117}
118
119#define _Q(_name, _query_type, _type, _result_type) {                \
120	.name        = _name,                                            \
121	.query_type  = _query_type,                                      \
122	.type        = PIPE_DRIVER_QUERY_TYPE_ ## _type,                 \
123	.result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_ ## _result_type,   \
124	.group_id    = ~(unsigned)0,                                     \
125}
126
127#define FQ(_name, _query_type, _type, _result_type) \
128	_Q(_name, FD_QUERY_ ## _query_type, _type, _result_type)
129
130#define PQ(_name, _query_type, _type, _result_type) \
131	_Q(_name, PIPE_QUERY_ ## _query_type, _type, _result_type)
132
133static const struct pipe_driver_query_info sw_query_list[] = {
134	FQ("draw-calls", DRAW_CALLS, UINT64, AVERAGE),
135	FQ("batches", BATCH_TOTAL, UINT64, AVERAGE),
136	FQ("batches-sysmem", BATCH_SYSMEM, UINT64, AVERAGE),
137	FQ("batches-gmem", BATCH_GMEM, UINT64, AVERAGE),
138	FQ("batches-nondraw", BATCH_NONDRAW, UINT64, AVERAGE),
139	FQ("restores", BATCH_RESTORE, UINT64, AVERAGE),
140	PQ("prims-emitted", PRIMITIVES_EMITTED, UINT64, AVERAGE),
141	FQ("staging", STAGING_UPLOADS, UINT64, AVERAGE),
142	FQ("shadow", SHADOW_UPLOADS, UINT64, AVERAGE),
143	FQ("vsregs", VS_REGS, FLOAT, AVERAGE),
144	FQ("fsregs", FS_REGS, FLOAT, AVERAGE),
145};
146
147static int
148fd_get_driver_query_info(struct pipe_screen *pscreen,
149		unsigned index, struct pipe_driver_query_info *info)
150{
151	struct fd_screen *screen = fd_screen(pscreen);
152
153	if (!info)
154		return ARRAY_SIZE(sw_query_list) + screen->num_perfcntr_queries;
155
156	if (index >= ARRAY_SIZE(sw_query_list)) {
157		index -= ARRAY_SIZE(sw_query_list);
158		if (index >= screen->num_perfcntr_queries)
159			return 0;
160		*info = screen->perfcntr_queries[index];
161		return 1;
162	}
163
164	*info = sw_query_list[index];
165	return 1;
166}
167
168static int
169fd_get_driver_query_group_info(struct pipe_screen *pscreen, unsigned index,
170		struct pipe_driver_query_group_info *info)
171{
172	struct fd_screen *screen = fd_screen(pscreen);
173
174	if (!info)
175		return screen->num_perfcntr_groups;
176
177	if (index >= screen->num_perfcntr_groups)
178		return 0;
179
180	const struct fd_perfcntr_group *g = &screen->perfcntr_groups[index];
181
182	info->name = g->name;
183	info->max_active_queries = g->num_counters;
184	info->num_queries = g->num_countables;
185
186	return 1;
187}
188
189static void
190fd_set_active_query_state(struct pipe_context *pipe, boolean enable)
191{
192}
193
194static void
195setup_perfcntr_query_info(struct fd_screen *screen)
196{
197	unsigned num_queries = 0;
198
199	for (unsigned i = 0; i < screen->num_perfcntr_groups; i++)
200		num_queries += screen->perfcntr_groups[i].num_countables;
201
202	screen->perfcntr_queries =
203		calloc(num_queries, sizeof(screen->perfcntr_queries[0]));
204	screen->num_perfcntr_queries = num_queries;
205
206	unsigned idx = 0;
207	for (unsigned i = 0; i < screen->num_perfcntr_groups; i++) {
208		const struct fd_perfcntr_group *g = &screen->perfcntr_groups[i];
209		for (unsigned j = 0; j < g->num_countables; j++) {
210			struct pipe_driver_query_info *info =
211				&screen->perfcntr_queries[idx];
212			const struct fd_perfcntr_countable *c =
213				&g->countables[j];
214
215			info->name = c->name;
216			info->query_type = FD_QUERY_FIRST_PERFCNTR + idx;
217			info->type = c->query_type;
218			info->result_type = c->result_type;
219			info->group_id = i;
220			info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
221
222			idx++;
223		}
224	}
225}
226
227void
228fd_query_screen_init(struct pipe_screen *pscreen)
229{
230	pscreen->get_driver_query_info = fd_get_driver_query_info;
231	pscreen->get_driver_query_group_info = fd_get_driver_query_group_info;
232	setup_perfcntr_query_info(fd_screen(pscreen));
233}
234
235void
236fd_query_context_init(struct pipe_context *pctx)
237{
238	pctx->create_query = fd_create_query;
239	pctx->destroy_query = fd_destroy_query;
240	pctx->begin_query = fd_begin_query;
241	pctx->end_query = fd_end_query;
242	pctx->get_query_result = fd_get_query_result;
243	pctx->set_active_query_state = fd_set_active_query_state;
244	pctx->render_condition = fd_render_condition;
245}
246