6f2956ec6f412e433e85ee26d940a8c841d3be70
[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] = INFOX(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)
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 break;
84 default:
85 return NULL;
86 }
87
88 q = CALLOC_STRUCT(ilo_query);
89 if (!q)
90 return NULL;
91
92 q->type = query_type;
93 list_inithead(&q->list);
94
95 return (struct pipe_query *) q;
96 }
97
98 static void
99 ilo_destroy_query(struct pipe_context *pipe, struct pipe_query *query)
100 {
101 struct ilo_query *q = ilo_query(query);
102
103 if (q->bo)
104 intel_bo_unreference(q->bo);
105
106 FREE(q);
107 }
108
109 static void
110 ilo_begin_query(struct pipe_context *pipe, struct pipe_query *query)
111 {
112 struct ilo_context *ilo = ilo_context(pipe);
113 struct ilo_query *q = ilo_query(query);
114
115 q->active = true;
116
117 query_info[q->type].begin(ilo, q);
118 }
119
120 static void
121 ilo_end_query(struct pipe_context *pipe, struct pipe_query *query)
122 {
123 struct ilo_context *ilo = ilo_context(pipe);
124 struct ilo_query *q = ilo_query(query);
125
126 query_info[q->type].end(ilo, q);
127
128 /*
129 * some queries such as timestamp query does not require a call to
130 * begin_query() so q->active is always false
131 */
132 q->active = false;
133 }
134
135 /**
136 * The type (union pipe_query_result) indicates only the size of the buffer.
137 * Callers expect the result to be "serialized".
138 */
139 static void
140 serialize_query_data(unsigned type, const union pipe_query_result *data,
141 void *buf)
142 {
143 switch (type) {
144 case PIPE_QUERY_OCCLUSION_COUNTER:
145 case PIPE_QUERY_TIMESTAMP:
146 case PIPE_QUERY_TIME_ELAPSED:
147 case PIPE_QUERY_PRIMITIVES_GENERATED:
148 case PIPE_QUERY_PRIMITIVES_EMITTED:
149 {
150 uint64_t *r = buf;
151 r[0] = data->u64;
152 }
153 break;
154 default:
155 memset(buf, 0, sizeof(union pipe_query_result));
156 break;
157 }
158 }
159
160 static boolean
161 ilo_get_query_result(struct pipe_context *pipe, struct pipe_query *query,
162 boolean wait, union pipe_query_result *result)
163 {
164 struct ilo_context *ilo = ilo_context(pipe);
165 struct ilo_query *q = ilo_query(query);
166
167 if (q->active)
168 return false;
169
170 if (q->bo) {
171 if (intel_bo_references(ilo->cp->bo, q->bo))
172 ilo_cp_flush(ilo->cp);
173
174 if (!wait && intel_bo_is_busy(q->bo))
175 return false;
176
177 query_info[q->type].process(ilo, q);
178 }
179
180 if (result)
181 serialize_query_data(q->type, &q->data, (void *) result);
182
183 return true;
184 }
185
186 /**
187 * Allocate a query bo for reading hardware statistics.
188 *
189 * \param reg_count specifies how many registers need to be read.
190 * \param repeat_count specifies how many times the registers are read. If
191 * zero or negative, a 4KB bo is allocated.
192 */
193 bool
194 ilo_query_alloc_bo(struct ilo_query *q, int reg_count, int repeat_count,
195 struct intel_winsys *winsys)
196 {
197 const char *name;
198 int reg_total;
199
200 name = query_info[q->type].name;
201
202 reg_total = reg_count * repeat_count;
203 if (reg_total <= 0)
204 reg_total = 4096 / sizeof(uint64_t);
205
206 /* (re-)allocate the bo */
207 if (q->reg_total < reg_total) {
208 /* registers are 64-bit */
209 const int size = reg_total * sizeof(uint64_t);
210
211 if (q->bo)
212 intel_bo_unreference(q->bo);
213
214 q->bo = intel_winsys_alloc_buffer(winsys, name, size, 0);
215 q->reg_total = (q->bo) ? reg_total : 0;
216 }
217
218 /* avoid partial reads */
219 if (reg_count)
220 q->reg_total -= q->reg_total % reg_count;
221
222 q->reg_read = 0;
223
224 return (q->bo != NULL);
225 }
226
227 /**
228 * Initialize query-related functions.
229 */
230 void
231 ilo_init_query_functions(struct ilo_context *ilo)
232 {
233 ilo->base.create_query = ilo_create_query;
234 ilo->base.destroy_query = ilo_destroy_query;
235 ilo->base.begin_query = ilo_begin_query;
236 ilo->base.end_query = ilo_end_query;
237 ilo->base.get_query_result = ilo_get_query_result;
238 }