• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&timestamp.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 *)&timestamp, 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