gallium: add an index argument to create_query
[mesa.git] / src / gallium / drivers / ilo / ilo_query.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2013 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include "intel_winsys.h"
29
30 #include "ilo_3d.h"
31 #include "ilo_context.h"
32 #include "ilo_cp.h"
33 #include "ilo_query.h"
34
35 static const struct {
36 const char *name;
37
38 void (*begin)(struct ilo_context *ilo, struct ilo_query *q);
39 void (*end)(struct ilo_context *ilo, struct ilo_query *q);
40 void (*process)(struct ilo_context *ilo, struct ilo_query *q);
41 } query_info[PIPE_QUERY_TYPES] = {
42 #define INFO(prefix, desc) { \
43 .name = desc, \
44 .begin = prefix ## _begin_query, \
45 .end = prefix ## _end_query, \
46 .process = prefix ## _process_query, \
47 }
48 #define INFOX(prefix, desc) { desc, NULL, NULL, NULL, }
49
50 [PIPE_QUERY_OCCLUSION_COUNTER] = INFO(ilo_3d, "occlusion counter"),
51 [PIPE_QUERY_OCCLUSION_PREDICATE] = INFOX(ilo_3d, "occlusion pred."),
52 [PIPE_QUERY_TIMESTAMP] = INFO(ilo_3d, "timestamp"),
53 [PIPE_QUERY_TIMESTAMP_DISJOINT] = INFOX(ilo_3d, "timestamp disjoint"),
54 [PIPE_QUERY_TIME_ELAPSED] = INFO(ilo_3d, "time elapsed"),
55 [PIPE_QUERY_PRIMITIVES_GENERATED] = INFO(ilo_3d, "primitives generated"),
56 [PIPE_QUERY_PRIMITIVES_EMITTED] = INFO(ilo_3d, "primitives emitted"),
57 [PIPE_QUERY_SO_STATISTICS] = INFOX(ilo_3d, "so statistics"),
58 [PIPE_QUERY_SO_OVERFLOW_PREDICATE] = INFOX(ilo_3d, "so overflow pred."),
59 [PIPE_QUERY_GPU_FINISHED] = INFOX(ilo_3d, "gpu finished"),
60 [PIPE_QUERY_PIPELINE_STATISTICS] = INFO(ilo_3d, "pipeline statistics"),
61
62 #undef INFO
63 #undef INFOX
64 };
65
66 static inline struct ilo_query *
67 ilo_query(struct pipe_query *query)
68 {
69 return (struct ilo_query *) query;
70 }
71
72 static struct pipe_query *
73 ilo_create_query(struct pipe_context *pipe, unsigned query_type, unsigned index)
74 {
75 struct ilo_query *q;
76
77 switch (query_type) {
78 case PIPE_QUERY_OCCLUSION_COUNTER:
79 case PIPE_QUERY_TIMESTAMP:
80 case PIPE_QUERY_TIME_ELAPSED:
81 case PIPE_QUERY_PRIMITIVES_GENERATED:
82 case PIPE_QUERY_PRIMITIVES_EMITTED:
83 case PIPE_QUERY_PIPELINE_STATISTICS:
84 break;
85 default:
86 return NULL;
87 }
88
89 q = CALLOC_STRUCT(ilo_query);
90 if (!q)
91 return NULL;
92
93 q->type = query_type;
94 list_inithead(&q->list);
95
96 return (struct pipe_query *) q;
97 }
98
99 static void
100 ilo_destroy_query(struct pipe_context *pipe, struct pipe_query *query)
101 {
102 struct ilo_query *q = ilo_query(query);
103
104 if (q->bo)
105 intel_bo_unreference(q->bo);
106
107 FREE(q);
108 }
109
110 static void
111 ilo_begin_query(struct pipe_context *pipe, struct pipe_query *query)
112 {
113 struct ilo_context *ilo = ilo_context(pipe);
114 struct ilo_query *q = ilo_query(query);
115
116 q->active = true;
117
118 query_info[q->type].begin(ilo, q);
119 }
120
121 static void
122 ilo_end_query(struct pipe_context *pipe, struct pipe_query *query)
123 {
124 struct ilo_context *ilo = ilo_context(pipe);
125 struct ilo_query *q = ilo_query(query);
126
127 query_info[q->type].end(ilo, q);
128
129 /*
130 * some queries such as timestamp query does not require a call to
131 * begin_query() so q->active is always false
132 */
133 q->active = false;
134 }
135
136 /**
137 * The type (union pipe_query_result) indicates only the size of the buffer.
138 * Callers expect the result to be "serialized".
139 */
140 static void
141 serialize_query_data(unsigned type, const union pipe_query_result *data,
142 void *buf)
143 {
144 switch (type) {
145 case PIPE_QUERY_OCCLUSION_COUNTER:
146 case PIPE_QUERY_TIMESTAMP:
147 case PIPE_QUERY_TIME_ELAPSED:
148 case PIPE_QUERY_PRIMITIVES_GENERATED:
149 case PIPE_QUERY_PRIMITIVES_EMITTED:
150 {
151 uint64_t *r = buf;
152 r[0] = data->u64;
153 }
154 break;
155 case PIPE_QUERY_PIPELINE_STATISTICS:
156 {
157 uint64_t *r = buf;
158 r[0] = data->pipeline_statistics.ia_vertices;
159 r[1] = data->pipeline_statistics.ia_primitives;
160 r[2] = data->pipeline_statistics.vs_invocations;
161 r[3] = data->pipeline_statistics.gs_invocations;
162 r[4] = data->pipeline_statistics.gs_primitives;
163 r[5] = data->pipeline_statistics.c_invocations;
164 r[6] = data->pipeline_statistics.c_primitives;
165 r[7] = data->pipeline_statistics.ps_invocations;
166 r[8] = data->pipeline_statistics.hs_invocations;
167 r[9] = data->pipeline_statistics.ds_invocations;
168 r[10] = data->pipeline_statistics.cs_invocations;
169 }
170 break;
171 default:
172 memset(buf, 0, sizeof(union pipe_query_result));
173 break;
174 }
175 }
176
177 static boolean
178 ilo_get_query_result(struct pipe_context *pipe, struct pipe_query *query,
179 boolean wait, union pipe_query_result *result)
180 {
181 struct ilo_context *ilo = ilo_context(pipe);
182 struct ilo_query *q = ilo_query(query);
183
184 if (q->active)
185 return false;
186
187 if (q->bo) {
188 if (intel_bo_has_reloc(ilo->cp->bo, q->bo))
189 ilo_cp_flush(ilo->cp, "syncing for queries");
190
191 if (!wait && intel_bo_is_busy(q->bo))
192 return false;
193
194 query_info[q->type].process(ilo, q);
195 }
196
197 if (result)
198 serialize_query_data(q->type, &q->data, (void *) result);
199
200 return true;
201 }
202
203 /**
204 * Allocate a query bo for reading hardware statistics.
205 *
206 * \param reg_count specifies how many registers need to be read.
207 * \param repeat_count specifies how many times the registers are read. If
208 * zero or negative, a 4KB bo is allocated.
209 */
210 bool
211 ilo_query_alloc_bo(struct ilo_query *q, int reg_count, int repeat_count,
212 struct intel_winsys *winsys)
213 {
214 const char *name;
215 int reg_total;
216
217 name = query_info[q->type].name;
218
219 reg_total = reg_count * repeat_count;
220 if (reg_total <= 0)
221 reg_total = 4096 / sizeof(uint64_t);
222
223 /* (re-)allocate the bo */
224 if (q->reg_total < reg_total) {
225 /* registers are 64-bit */
226 const int size = reg_total * sizeof(uint64_t);
227
228 if (q->bo)
229 intel_bo_unreference(q->bo);
230
231 q->bo = intel_winsys_alloc_buffer(winsys,
232 name, size, INTEL_DOMAIN_INSTRUCTION);
233 q->reg_total = (q->bo) ? reg_total : 0;
234 }
235
236 /* avoid partial reads */
237 if (reg_count)
238 q->reg_total -= q->reg_total % reg_count;
239
240 q->reg_read = 0;
241
242 return (q->bo != NULL);
243 }
244
245 /**
246 * Initialize query-related functions.
247 */
248 void
249 ilo_init_query_functions(struct ilo_context *ilo)
250 {
251 ilo->base.create_query = ilo_create_query;
252 ilo->base.destroy_query = ilo_destroy_query;
253 ilo->base.begin_query = ilo_begin_query;
254 ilo->base.end_query = ilo_end_query;
255 ilo->base.get_query_result = ilo_get_query_result;
256 }