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
);
56 realloc_query_bo(struct fd_context
*ctx
, struct fd_acc_query
*aq
)
58 struct fd_resource
*rsc
;
61 pipe_resource_reference(&aq
->prsc
, NULL
);
63 aq
->prsc
= pipe_buffer_create(&ctx
->screen
->base
,
64 PIPE_BIND_QUERY_BUFFER
, 0, 0x1000);
66 /* don't assume the buffer is zero-initialized: */
67 rsc
= fd_resource(aq
->prsc
);
69 fd_bo_cpu_prep(rsc
->bo
, ctx
->screen
->pipe
, DRM_FREEDRENO_PREP_WRITE
);
71 map
= fd_bo_map(rsc
->bo
);
72 memset(map
, 0, aq
->provider
->size
);
73 fd_bo_cpu_fini(rsc
->bo
);
77 fd_acc_begin_query(struct fd_context
*ctx
, struct fd_query
*q
)
79 struct fd_batch
*batch
= ctx
->batch
;
80 struct fd_acc_query
*aq
= fd_acc_query(q
);
81 const struct fd_acc_sample_provider
*p
= aq
->provider
;
83 DBG("%p: active=%d", q
, q
->active
);
85 /* ->begin_query() discards previous results, so realloc bo: */
86 realloc_query_bo(ctx
, aq
);
88 /* then resume query if needed to collect first sample: */
89 if (batch
&& is_active(aq
, batch
->stage
))
92 /* add to active list: */
93 assert(list_empty(&aq
->node
));
94 list_addtail(&aq
->node
, &ctx
->acc_active_queries
);
100 fd_acc_end_query(struct fd_context
*ctx
, struct fd_query
*q
)
102 struct fd_batch
*batch
= ctx
->batch
;
103 struct fd_acc_query
*aq
= fd_acc_query(q
);
104 const struct fd_acc_sample_provider
*p
= aq
->provider
;
106 DBG("%p: active=%d", q
, q
->active
);
108 if (batch
&& is_active(aq
, batch
->stage
))
111 /* remove from active list: */
112 list_delinit(&aq
->node
);
116 fd_acc_get_query_result(struct fd_context
*ctx
, struct fd_query
*q
,
117 boolean wait
, union pipe_query_result
*result
)
119 struct fd_acc_query
*aq
= fd_acc_query(q
);
120 const struct fd_acc_sample_provider
*p
= aq
->provider
;
121 struct fd_resource
*rsc
= fd_resource(aq
->prsc
);
123 DBG("%p: wait=%d, active=%d", q
, wait
, q
->active
);
125 assert(LIST_IS_EMPTY(&aq
->node
));
127 /* if !wait, then check the last sample (the one most likely to
128 * not be ready yet) and bail if it is not ready:
133 if (pending(rsc
, false)) {
134 /* piglit spec@arb_occlusion_query@occlusion_query_conform
135 * test, and silly apps perhaps, get stuck in a loop trying
136 * to get query result forever with wait==false.. we don't
137 * wait to flush unnecessarily but we also don't want to
140 if (aq
->no_wait_cnt
++ > 5)
141 fd_batch_flush(rsc
->write_batch
, false);
145 ret
= fd_bo_cpu_prep(rsc
->bo
, ctx
->screen
->pipe
,
146 DRM_FREEDRENO_PREP_READ
| DRM_FREEDRENO_PREP_NOSYNC
);
150 fd_bo_cpu_fini(rsc
->bo
);
153 if (rsc
->write_batch
)
154 fd_batch_flush(rsc
->write_batch
, true);
156 /* get the result: */
157 fd_bo_cpu_prep(rsc
->bo
, ctx
->screen
->pipe
, DRM_FREEDRENO_PREP_READ
);
159 void *ptr
= fd_bo_map(rsc
->bo
);
160 p
->result(ctx
, ptr
, result
);
161 fd_bo_cpu_fini(rsc
->bo
);
166 static const struct fd_query_funcs acc_query_funcs
= {
167 .destroy_query
= fd_acc_destroy_query
,
168 .begin_query
= fd_acc_begin_query
,
169 .end_query
= fd_acc_end_query
,
170 .get_query_result
= fd_acc_get_query_result
,
174 fd_acc_create_query(struct fd_context
*ctx
, unsigned query_type
)
176 struct fd_acc_query
*aq
;
178 int idx
= pidx(query_type
);
180 if ((idx
< 0) || !ctx
->acc_sample_providers
[idx
])
183 aq
= CALLOC_STRUCT(fd_acc_query
);
187 DBG("%p: query_type=%u", aq
, query_type
);
189 aq
->provider
= ctx
->acc_sample_providers
[idx
];
191 list_inithead(&aq
->node
);
194 q
->funcs
= &acc_query_funcs
;
195 q
->type
= query_type
;
201 fd_acc_query_set_stage(struct fd_batch
*batch
, enum fd_render_stage stage
)
203 if (stage
!= batch
->stage
) {
204 struct fd_acc_query
*aq
;
205 LIST_FOR_EACH_ENTRY(aq
, &batch
->ctx
->acc_active_queries
, node
) {
206 const struct fd_acc_sample_provider
*p
= aq
->provider
;
208 bool was_active
= is_active(aq
, batch
->stage
);
209 bool now_active
= is_active(aq
, stage
);
211 if (now_active
&& !was_active
)
212 p
->resume(aq
, batch
);
213 else if (was_active
&& !now_active
)
220 fd_acc_query_register_provider(struct pipe_context
*pctx
,
221 const struct fd_acc_sample_provider
*provider
)
223 struct fd_context
*ctx
= fd_context(pctx
);
224 int idx
= pidx(provider
->query_type
);
226 assert((0 <= idx
) && (idx
< MAX_HW_SAMPLE_PROVIDERS
));
227 assert(!ctx
->acc_sample_providers
[idx
]);
229 ctx
->acc_sample_providers
[idx
] = provider
;