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"
37 is_active(struct fd_acc_query
*aq
, enum fd_render_stage stage
)
39 return !!(aq
->provider
->active
& stage
);
43 fd_acc_destroy_query(struct fd_context
*ctx
, struct fd_query
*q
)
45 struct fd_acc_query
*aq
= fd_acc_query(q
);
47 DBG("%p: active=%d", q
, q
->active
);
49 pipe_resource_reference(&aq
->prsc
, NULL
);
57 realloc_query_bo(struct fd_context
*ctx
, struct fd_acc_query
*aq
)
59 struct fd_resource
*rsc
;
62 pipe_resource_reference(&aq
->prsc
, NULL
);
64 aq
->prsc
= pipe_buffer_create(&ctx
->screen
->base
,
65 PIPE_BIND_QUERY_BUFFER
, 0, 0x1000);
67 /* don't assume the buffer is zero-initialized: */
68 rsc
= fd_resource(aq
->prsc
);
70 fd_bo_cpu_prep(rsc
->bo
, ctx
->pipe
, DRM_FREEDRENO_PREP_WRITE
);
72 map
= fd_bo_map(rsc
->bo
);
73 memset(map
, 0, aq
->size
);
74 fd_bo_cpu_fini(rsc
->bo
);
78 fd_acc_begin_query(struct fd_context
*ctx
, struct fd_query
*q
)
80 struct fd_batch
*batch
= fd_context_batch(ctx
);
81 struct fd_acc_query
*aq
= fd_acc_query(q
);
82 const struct fd_acc_sample_provider
*p
= aq
->provider
;
84 DBG("%p: active=%d", q
, q
->active
);
86 /* ->begin_query() discards previous results, so realloc bo: */
87 realloc_query_bo(ctx
, aq
);
89 /* then resume query if needed to collect first sample: */
90 if (batch
&& is_active(aq
, batch
->stage
))
93 /* add to active list: */
94 assert(list_empty(&aq
->node
));
95 list_addtail(&aq
->node
, &ctx
->acc_active_queries
);
101 fd_acc_end_query(struct fd_context
*ctx
, struct fd_query
*q
)
103 struct fd_batch
*batch
= fd_context_batch(ctx
);
104 struct fd_acc_query
*aq
= fd_acc_query(q
);
105 const struct fd_acc_sample_provider
*p
= aq
->provider
;
107 DBG("%p: active=%d", q
, q
->active
);
109 if (batch
&& is_active(aq
, batch
->stage
))
112 /* remove from active list: */
113 list_delinit(&aq
->node
);
117 fd_acc_get_query_result(struct fd_context
*ctx
, struct fd_query
*q
,
118 bool wait
, union pipe_query_result
*result
)
120 struct fd_acc_query
*aq
= fd_acc_query(q
);
121 const struct fd_acc_sample_provider
*p
= aq
->provider
;
122 struct fd_resource
*rsc
= fd_resource(aq
->prsc
);
124 DBG("%p: wait=%d, active=%d", q
, wait
, q
->active
);
126 assert(LIST_IS_EMPTY(&aq
->node
));
128 /* if !wait, then check the last sample (the one most likely to
129 * not be ready yet) and bail if it is not ready:
134 if (pending(rsc
, false)) {
135 /* piglit spec@arb_occlusion_query@occlusion_query_conform
136 * test, and silly apps perhaps, get stuck in a loop trying
137 * to get query result forever with wait==false.. we don't
138 * wait to flush unnecessarily but we also don't want to
141 if (aq
->no_wait_cnt
++ > 5)
142 fd_batch_flush(rsc
->write_batch
, false);
146 ret
= fd_bo_cpu_prep(rsc
->bo
, ctx
->pipe
,
147 DRM_FREEDRENO_PREP_READ
| DRM_FREEDRENO_PREP_NOSYNC
);
151 fd_bo_cpu_fini(rsc
->bo
);
154 if (rsc
->write_batch
)
155 fd_batch_flush(rsc
->write_batch
, true);
157 /* get the result: */
158 fd_bo_cpu_prep(rsc
->bo
, ctx
->pipe
, DRM_FREEDRENO_PREP_READ
);
160 void *ptr
= fd_bo_map(rsc
->bo
);
161 p
->result(aq
, ptr
, result
);
162 fd_bo_cpu_fini(rsc
->bo
);
167 static const struct fd_query_funcs acc_query_funcs
= {
168 .destroy_query
= fd_acc_destroy_query
,
169 .begin_query
= fd_acc_begin_query
,
170 .end_query
= fd_acc_end_query
,
171 .get_query_result
= fd_acc_get_query_result
,
175 fd_acc_create_query2(struct fd_context
*ctx
, unsigned query_type
,
176 unsigned index
, const struct fd_acc_sample_provider
*provider
)
178 struct fd_acc_query
*aq
;
181 aq
= CALLOC_STRUCT(fd_acc_query
);
185 DBG("%p: query_type=%u", aq
, query_type
);
187 aq
->provider
= provider
;
188 aq
->size
= provider
->size
;
190 list_inithead(&aq
->node
);
193 q
->funcs
= &acc_query_funcs
;
194 q
->type
= query_type
;
201 fd_acc_create_query(struct fd_context
*ctx
, unsigned query_type
,
204 int idx
= pidx(query_type
);
206 if ((idx
< 0) || !ctx
->acc_sample_providers
[idx
])
209 return fd_acc_create_query2(ctx
, query_type
, index
,
210 ctx
->acc_sample_providers
[idx
]);
214 fd_acc_query_set_stage(struct fd_batch
*batch
, enum fd_render_stage stage
)
216 if (stage
!= batch
->stage
) {
217 struct fd_acc_query
*aq
;
218 LIST_FOR_EACH_ENTRY(aq
, &batch
->ctx
->acc_active_queries
, node
) {
219 const struct fd_acc_sample_provider
*p
= aq
->provider
;
221 bool was_active
= is_active(aq
, batch
->stage
);
222 bool now_active
= is_active(aq
, stage
);
224 if (now_active
&& !was_active
)
225 p
->resume(aq
, batch
);
226 else if (was_active
&& !now_active
)
233 fd_acc_query_register_provider(struct pipe_context
*pctx
,
234 const struct fd_acc_sample_provider
*provider
)
236 struct fd_context
*ctx
= fd_context(pctx
);
237 int idx
= pidx(provider
->query_type
);
239 assert((0 <= idx
) && (idx
< MAX_HW_SAMPLE_PROVIDERS
));
240 assert(!ctx
->acc_sample_providers
[idx
]);
242 ctx
->acc_sample_providers
[idx
] = provider
;