2 * Copyright (C) 2017 Rob Clark <robclark@freedesktop.org>
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:
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
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
24 * Rob Clark <robclark@freedesktop.org>
27 #include "util/u_memory.h"
28 #include "util/u_inlines.h"
30 #include "freedreno_query_acc.h"
31 #include "freedreno_context.h"
32 #include "freedreno_resource.h"
33 #include "freedreno_util.h"
36 fd_acc_destroy_query(struct fd_context
*ctx
, struct fd_query
*q
)
38 struct fd_acc_query
*aq
= fd_acc_query(q
);
42 pipe_resource_reference(&aq
->prsc
, NULL
);
50 realloc_query_bo(struct fd_context
*ctx
, struct fd_acc_query
*aq
)
52 struct fd_resource
*rsc
;
55 pipe_resource_reference(&aq
->prsc
, NULL
);
57 aq
->prsc
= pipe_buffer_create(&ctx
->screen
->base
,
58 PIPE_BIND_QUERY_BUFFER
, 0, 0x1000);
60 /* don't assume the buffer is zero-initialized: */
61 rsc
= fd_resource(aq
->prsc
);
63 fd_bo_cpu_prep(rsc
->bo
, ctx
->pipe
, DRM_FREEDRENO_PREP_WRITE
);
65 map
= fd_bo_map(rsc
->bo
);
66 memset(map
, 0, aq
->size
);
67 fd_bo_cpu_fini(rsc
->bo
);
71 fd_acc_query_pause(struct fd_acc_query
*aq
)
73 const struct fd_acc_sample_provider
*p
= aq
->provider
;
78 p
->pause(aq
, aq
->batch
);
83 fd_acc_query_resume(struct fd_acc_query
*aq
, struct fd_batch
*batch
)
85 const struct fd_acc_sample_provider
*p
= aq
->provider
;
88 p
->resume(aq
, aq
->batch
);
90 fd_screen_lock(batch
->ctx
->screen
);
91 fd_batch_resource_write(batch
, fd_resource(aq
->prsc
));
92 fd_screen_unlock(batch
->ctx
->screen
);
96 fd_acc_begin_query(struct fd_context
*ctx
, struct fd_query
*q
)
98 struct fd_acc_query
*aq
= fd_acc_query(q
);
102 /* ->begin_query() discards previous results, so realloc bo: */
103 realloc_query_bo(ctx
, aq
);
105 /* Signal that we need to update the active queries on the next draw */
106 ctx
->update_active_queries
= true;
108 /* add to active list: */
109 assert(list_is_empty(&aq
->node
));
110 list_addtail(&aq
->node
, &ctx
->acc_active_queries
);
112 /* TIMESTAMP/GPU_FINISHED and don't do normal bracketing at draw time, we
113 * need to just emit the capture at this moment.
115 if (skip_begin_query(q
->type
))
116 fd_acc_query_resume(aq
, fd_context_batch(ctx
));
120 fd_acc_end_query(struct fd_context
*ctx
, struct fd_query
*q
)
122 struct fd_acc_query
*aq
= fd_acc_query(q
);
126 fd_acc_query_pause(aq
);
128 /* remove from active list: */
129 list_delinit(&aq
->node
);
133 fd_acc_get_query_result(struct fd_context
*ctx
, struct fd_query
*q
,
134 bool wait
, union pipe_query_result
*result
)
136 struct fd_acc_query
*aq
= fd_acc_query(q
);
137 const struct fd_acc_sample_provider
*p
= aq
->provider
;
138 struct fd_resource
*rsc
= fd_resource(aq
->prsc
);
140 DBG("%p: wait=%d", q
, wait
);
142 assert(list_is_empty(&aq
->node
));
144 /* if !wait, then check the last sample (the one most likely to
145 * not be ready yet) and bail if it is not ready:
150 if (pending(rsc
, false)) {
151 /* piglit spec@arb_occlusion_query@occlusion_query_conform
152 * test, and silly apps perhaps, get stuck in a loop trying
153 * to get query result forever with wait==false.. we don't
154 * wait to flush unnecessarily but we also don't want to
157 if (aq
->no_wait_cnt
++ > 5)
158 fd_batch_flush(rsc
->write_batch
);
162 ret
= fd_bo_cpu_prep(rsc
->bo
, ctx
->pipe
,
163 DRM_FREEDRENO_PREP_READ
| DRM_FREEDRENO_PREP_NOSYNC
);
167 fd_bo_cpu_fini(rsc
->bo
);
170 if (rsc
->write_batch
)
171 fd_batch_flush(rsc
->write_batch
);
173 /* get the result: */
174 fd_bo_cpu_prep(rsc
->bo
, ctx
->pipe
, DRM_FREEDRENO_PREP_READ
);
176 void *ptr
= fd_bo_map(rsc
->bo
);
177 p
->result(aq
, ptr
, result
);
178 fd_bo_cpu_fini(rsc
->bo
);
183 static const struct fd_query_funcs acc_query_funcs
= {
184 .destroy_query
= fd_acc_destroy_query
,
185 .begin_query
= fd_acc_begin_query
,
186 .end_query
= fd_acc_end_query
,
187 .get_query_result
= fd_acc_get_query_result
,
191 fd_acc_create_query2(struct fd_context
*ctx
, unsigned query_type
,
192 unsigned index
, const struct fd_acc_sample_provider
*provider
)
194 struct fd_acc_query
*aq
;
197 aq
= CALLOC_STRUCT(fd_acc_query
);
201 DBG("%p: query_type=%u", aq
, query_type
);
203 aq
->provider
= provider
;
204 aq
->size
= provider
->size
;
206 list_inithead(&aq
->node
);
209 q
->funcs
= &acc_query_funcs
;
210 q
->type
= query_type
;
217 fd_acc_create_query(struct fd_context
*ctx
, unsigned query_type
,
220 int idx
= pidx(query_type
);
222 if ((idx
< 0) || !ctx
->acc_sample_providers
[idx
])
225 return fd_acc_create_query2(ctx
, query_type
, index
,
226 ctx
->acc_sample_providers
[idx
]);
229 /* Called at clear/draw/blit time to enable/disable the appropriate queries in
230 * the batch (and transfer active querying between batches in the case of
234 fd_acc_query_set_stage(struct fd_batch
*batch
, enum fd_render_stage stage
)
236 struct fd_context
*ctx
= batch
->ctx
;
238 if (stage
!= batch
->stage
|| ctx
->update_active_queries
) {
239 struct fd_acc_query
*aq
;
240 LIST_FOR_EACH_ENTRY(aq
, &ctx
->acc_active_queries
, node
) {
241 bool batch_change
= aq
->batch
!= batch
;
242 bool was_active
= aq
->batch
!= NULL
;
243 bool now_active
= stage
!= FD_STAGE_NULL
&&
244 (ctx
->active_queries
|| aq
->provider
->always
);
246 if (was_active
&& (!now_active
|| batch_change
))
247 fd_acc_query_pause(aq
);
248 if (now_active
&& (!was_active
|| batch_change
))
249 fd_acc_query_resume(aq
, batch
);
253 ctx
->update_active_queries
= false;
257 fd_acc_query_register_provider(struct pipe_context
*pctx
,
258 const struct fd_acc_sample_provider
*provider
)
260 struct fd_context
*ctx
= fd_context(pctx
);
261 int idx
= pidx(provider
->query_type
);
263 assert((0 <= idx
) && (idx
< MAX_HW_SAMPLE_PROVIDERS
));
264 assert(!ctx
->acc_sample_providers
[idx
]);
266 ctx
->acc_sample_providers
[idx
] = provider
;