1 /*
2 * Copyright © 2014 Broadcom
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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "v3d_query.h"
25
26 int
v3d_get_driver_query_group_info(struct pipe_screen * pscreen,unsigned index,struct pipe_driver_query_group_info * info)27 v3d_get_driver_query_group_info(struct pipe_screen *pscreen, unsigned index,
28 struct pipe_driver_query_group_info *info)
29 {
30 struct v3d_screen *screen = v3d_screen(pscreen);
31
32 if (!screen->has_perfmon)
33 return 0;
34
35 if (!info)
36 return 1;
37
38 if (index > 0)
39 return 0;
40
41 info->name = "V3D counters";
42 info->max_active_queries = DRM_V3D_MAX_PERF_COUNTERS;
43 info->num_queries = screen->perfcnt->max_perfcnt;
44
45 return 1;
46 }
47
48 int
v3d_get_driver_query_info(struct pipe_screen * pscreen,unsigned index,struct pipe_driver_query_info * info)49 v3d_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
50 struct pipe_driver_query_info *info)
51 {
52 struct v3d_screen *screen = v3d_screen(pscreen);
53 struct v3d_perfcntr_desc *desc;
54
55 if (!screen->has_perfmon)
56 return 0;
57
58 if (!info)
59 return screen->perfcnt->max_perfcnt;
60
61 desc = v3d_perfcntrs_get_by_index(screen->perfcnt, index);
62 if (!desc)
63 return 0;
64
65 info->name = desc->name;
66 info->group_id = 0;
67 info->query_type = PIPE_QUERY_DRIVER_SPECIFIC + index;
68 info->result_type = PIPE_DRIVER_QUERY_RESULT_TYPE_CUMULATIVE;
69 info->type = PIPE_DRIVER_QUERY_TYPE_UINT64;
70 info->flags = PIPE_DRIVER_QUERY_FLAG_BATCH;
71
72 return 1;
73 }
74
75 static struct pipe_query *
v3d_create_query(struct pipe_context * pctx,unsigned query_type,unsigned index)76 v3d_create_query(struct pipe_context *pctx, unsigned query_type, unsigned index)
77 {
78 struct v3d_context *v3d = v3d_context(pctx);
79
80 return v3d_create_query_pipe(v3d, query_type, index);
81 }
82
83 static struct pipe_query *
v3d_create_batch_query(struct pipe_context * pctx,unsigned num_queries,unsigned * query_types)84 v3d_create_batch_query(struct pipe_context *pctx, unsigned num_queries,
85 unsigned *query_types)
86 {
87 struct v3d_context *v3d = v3d_context(pctx);
88
89 return v3d_create_batch_query_pipe(v3d, num_queries, query_types);
90 }
91
92 static void
v3d_destroy_query(struct pipe_context * pctx,struct pipe_query * query)93 v3d_destroy_query(struct pipe_context *pctx, struct pipe_query *query)
94 {
95 struct v3d_context *v3d = v3d_context(pctx);
96 struct v3d_query *q = (struct v3d_query *)query;
97
98 q->funcs->destroy_query(v3d, q);
99 }
100
101 static bool
v3d_begin_query(struct pipe_context * pctx,struct pipe_query * query)102 v3d_begin_query(struct pipe_context *pctx, struct pipe_query *query)
103 {
104 struct v3d_context *v3d = v3d_context(pctx);
105 struct v3d_query *q = (struct v3d_query *)query;
106
107 return q->funcs->begin_query(v3d, q);
108 }
109
110 static bool
v3d_end_query(struct pipe_context * pctx,struct pipe_query * query)111 v3d_end_query(struct pipe_context *pctx, struct pipe_query *query)
112 {
113 struct v3d_context *v3d = v3d_context(pctx);
114 struct v3d_query *q = (struct v3d_query *)query;
115
116 return q->funcs->end_query(v3d, q);
117 }
118
119 static bool
v3d_get_query_result(struct pipe_context * pctx,struct pipe_query * query,bool wait,union pipe_query_result * vresult)120 v3d_get_query_result(struct pipe_context *pctx, struct pipe_query *query,
121 bool wait, union pipe_query_result *vresult)
122 {
123 struct v3d_context *v3d = v3d_context(pctx);
124 struct v3d_query *q = (struct v3d_query *)query;
125
126 return q->funcs->get_query_result(v3d, q, wait, vresult);
127 }
128
129 static void
v3d_set_active_query_state(struct pipe_context * pctx,bool enable)130 v3d_set_active_query_state(struct pipe_context *pctx, bool enable)
131 {
132 struct v3d_context *v3d = v3d_context(pctx);
133
134 v3d->active_queries = enable;
135 v3d->dirty |= V3D_DIRTY_OQ;
136 v3d->dirty |= V3D_DIRTY_STREAMOUT;
137 }
138
139 static void
v3d_render_condition(struct pipe_context * pipe,struct pipe_query * query,bool condition,enum pipe_render_cond_flag mode)140 v3d_render_condition(struct pipe_context *pipe,
141 struct pipe_query *query,
142 bool condition,
143 enum pipe_render_cond_flag mode)
144 {
145 struct v3d_context *v3d = v3d_context(pipe);
146
147 v3d->cond_query = query;
148 v3d->cond_cond = condition;
149 v3d->cond_mode = mode;
150 }
151
152 static void
extension_set(struct drm_v3d_extension * ext,struct drm_v3d_extension * next,uint32_t id,uintptr_t flags)153 extension_set(struct drm_v3d_extension *ext, struct drm_v3d_extension *next,
154 uint32_t id, uintptr_t flags)
155 {
156 ext->next = (uintptr_t)(void *)next;
157 ext->id = id;
158 ext->flags = flags;
159 }
160
161 static struct drm_v3d_sem *
in_syncs_set(struct v3d_context * v3d,uint32_t * count,struct v3d_submit_sync_info * sync_info)162 in_syncs_set(struct v3d_context *v3d, uint32_t *count,
163 struct v3d_submit_sync_info *sync_info)
164 {
165 uint32_t nsyncs = sync_info->wait_count;
166
167 *count = nsyncs;
168
169 struct drm_v3d_sem *syncs =
170 rzalloc_array(v3d, struct drm_v3d_sem, *count);
171
172 if (!syncs) return NULL;
173
174 for (int i = 0; i < nsyncs; i++) {
175 syncs[i].handle = sync_info->waits[i];
176 }
177
178 assert(*count == nsyncs);
179
180 return syncs;
181 }
182
183 static struct drm_v3d_sem *
out_syncs_set(struct v3d_context * v3d,uint32_t * count,struct v3d_submit_sync_info * sync_info)184 out_syncs_set(struct v3d_context *v3d, uint32_t *count,
185 struct v3d_submit_sync_info *sync_info)
186 {
187 (*count) = sync_info->signal_count;
188
189 struct drm_v3d_sem *syncs =
190 rzalloc_array(v3d, struct drm_v3d_sem, *count);
191
192 if (!syncs) return NULL;
193
194 for (unsigned i = 0; i < *count; i++) {
195 syncs[i].handle = sync_info->signals[i];
196 }
197
198 return syncs;
199 }
200
201 static void
multisync_set(struct v3d_context * v3d,struct drm_v3d_multi_sync * ms,struct v3d_submit_sync_info * sync_info,struct drm_v3d_extension * next,uint32_t wait_stage)202 multisync_set(struct v3d_context *v3d, struct drm_v3d_multi_sync *ms,
203 struct v3d_submit_sync_info *sync_info,
204 struct drm_v3d_extension *next, uint32_t wait_stage)
205 {
206 uint32_t ocount = 0, icount = 0;
207 struct drm_v3d_sem *out_syncs = NULL, *in_syncs = NULL;
208
209 in_syncs = in_syncs_set(v3d, &icount, sync_info);
210 if (!in_syncs && icount) goto out;
211
212 out_syncs = out_syncs_set(v3d, &ocount, sync_info);
213 if (!out_syncs) goto out;
214
215 extension_set(&ms->base, next, DRM_V3D_EXT_ID_MULTI_SYNC, 0);
216 ms->wait_stage = wait_stage;
217 ms->out_sync_count = ocount;
218 ms->out_syncs = (uintptr_t)(void *)out_syncs;
219 ms->in_sync_count = icount;
220 ms->in_syncs = (uintptr_t)(void *)in_syncs;
221
222 return;
223
224 out:
225 fprintf(stderr, "Multisync Set Failed\n");
226 if (in_syncs) {
227 free(in_syncs);
228 }
229 }
230
231 static void
multisync_free(struct drm_v3d_multi_sync * ms)232 multisync_free(struct drm_v3d_multi_sync *ms)
233 {
234 ralloc_free((void *)(uintptr_t)ms->out_syncs);
235 ralloc_free((void *)(uintptr_t)ms->in_syncs);
236 }
237
238 uint64_t
v3d_get_timestamp(struct pipe_context * pctx)239 v3d_get_timestamp(struct pipe_context *pctx)
240 {
241 /* Calling glGetInteger64v with GL_TIMESTAMP will return the GPU
242 * timestamp when all previously given commands have issued, but not
243 * necessarily completed
244 */
245 v3d_flush(pctx);
246
247 /* Use os_time_get_nano as all of our timestamps come from the CPU clock */
248 return os_time_get_nano();
249 }
250
251 void
v3d_submit_timestamp_query(struct pipe_context * pctx,struct v3d_bo * bo,uint32_t sync,uint32_t offset)252 v3d_submit_timestamp_query(struct pipe_context *pctx, struct v3d_bo *bo,
253 uint32_t sync, uint32_t offset)
254 {
255 struct v3d_context *v3d = v3d_context(pctx);
256 struct v3d_screen *screen = v3d->screen;
257 int ret;
258
259 /* check for multisync support */
260 assert(screen->has_multisync);
261
262 /* check for a valid bo to store the timestamp result */
263 assert(bo);
264
265 /* check for a valid syncobj */
266 assert(sync);
267
268 struct drm_v3d_timestamp_query timestamp = {0};
269
270 extension_set(×tamp.base, NULL, DRM_V3D_EXT_ID_CPU_TIMESTAMP_QUERY, 0);
271
272 timestamp.count = 1;
273 timestamp.offsets = (uintptr_t)(void *)&offset;
274 timestamp.syncs = (uintptr_t)(void *)&sync;
275
276 struct v3d_submit_sync_info sync_info = {
277 .wait_count = 1,
278 .waits = &v3d->out_sync,
279 .signal_count = 1,
280 .signals = &v3d->out_sync,
281 };
282
283 struct drm_v3d_multi_sync ms = {0};
284
285 multisync_set(v3d, &ms, &sync_info, (void *)×tamp, V3D_CPU);
286
287 struct drm_v3d_submit_cpu submit = {0};
288
289 submit.bo_handle_count = 1;
290 submit.bo_handles = (uintptr_t)(void *)&bo->handle;
291 submit.flags |= DRM_V3D_SUBMIT_EXTENSION;
292 submit.extensions = (uintptr_t)(void *)&ms;
293
294 ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_SUBMIT_CPU, &submit);
295 if (ret)
296 fprintf(stderr, "Failed to submit cpu job: %s\n", strerror(errno));
297
298 multisync_free(&ms);
299 }
300
301 void
v3d_query_init(struct pipe_context * pctx)302 v3d_query_init(struct pipe_context *pctx)
303 {
304 pctx->create_query = v3d_create_query;
305 pctx->create_batch_query = v3d_create_batch_query;
306 pctx->destroy_query = v3d_destroy_query;
307 pctx->begin_query = v3d_begin_query;
308 pctx->end_query = v3d_end_query;
309 pctx->get_query_result = v3d_get_query_result;
310 pctx->set_active_query_state = v3d_set_active_query_state;
311 pctx->render_condition = v3d_render_condition;
312 pctx->get_timestamp = v3d_get_timestamp;
313 }
314