v3d: compute appropriate VPM memory configuration for geometry shader workloads
[mesa.git] / src / gallium / drivers / zink / zink_query.c
1 #include "zink_query.h"
2
3 #include "zink_context.h"
4 #include "zink_screen.h"
5
6 #include "util/u_dump.h"
7 #include "util/u_inlines.h"
8 #include "util/u_memory.h"
9
10 struct zink_query {
11 enum pipe_query_type type;
12
13 VkQueryPool query_pool;
14 unsigned curr_query, num_queries;
15
16 VkQueryType vkqtype;
17 bool use_64bit;
18 bool precise;
19
20 struct list_head active_list;
21 };
22
23 static VkQueryType
24 convert_query_type(unsigned query_type, bool *use_64bit, bool *precise)
25 {
26 *use_64bit = false;
27 *precise = false;
28 switch (query_type) {
29 case PIPE_QUERY_OCCLUSION_COUNTER:
30 *precise = true;
31 *use_64bit = true;
32 case PIPE_QUERY_OCCLUSION_PREDICATE:
33 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
34 return VK_QUERY_TYPE_OCCLUSION;
35 case PIPE_QUERY_TIMESTAMP:
36 *use_64bit = true;
37 return VK_QUERY_TYPE_TIMESTAMP;
38 case PIPE_QUERY_PIPELINE_STATISTICS:
39 return VK_QUERY_TYPE_PIPELINE_STATISTICS;
40 default:
41 debug_printf("unknown query: %s\n",
42 util_str_query_type(query_type, true));
43 unreachable("zink: unknown query type");
44 }
45 }
46
47 static struct pipe_query *
48 zink_create_query(struct pipe_context *pctx,
49 unsigned query_type, unsigned index)
50 {
51 struct zink_screen *screen = zink_screen(pctx->screen);
52 struct zink_query *query = CALLOC_STRUCT(zink_query);
53 VkQueryPoolCreateInfo pool_create = {};
54
55 if (!query)
56 return NULL;
57
58 query->type = query_type;
59 query->vkqtype = convert_query_type(query_type, &query->use_64bit, &query->precise);
60 if (query->vkqtype == -1)
61 return NULL;
62
63 query->num_queries = query_type == PIPE_QUERY_TIMESTAMP ? 1 : 100;
64 query->curr_query = 0;
65
66 pool_create.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
67 pool_create.queryType = query->vkqtype;
68 pool_create.queryCount = query->num_queries;
69
70 VkResult status = vkCreateQueryPool(screen->dev, &pool_create, NULL, &query->query_pool);
71 if (status != VK_SUCCESS) {
72 FREE(query);
73 return NULL;
74 }
75 return (struct pipe_query *)query;
76 }
77
78 static void
79 zink_destroy_query(struct pipe_context *pctx,
80 struct pipe_query *q)
81 {
82 struct zink_screen *screen = zink_screen(pctx->screen);
83 struct zink_query *query = (struct zink_query *)q;
84
85 vkDestroyQueryPool(screen->dev, query->query_pool, NULL);
86 }
87
88 static void
89 begin_query(struct zink_context *ctx, struct zink_query *q)
90 {
91 VkQueryControlFlags flags = 0;
92 if (q->precise)
93 flags |= VK_QUERY_CONTROL_PRECISE_BIT;
94
95 struct zink_batch *batch = zink_curr_batch(ctx);
96 vkCmdBeginQuery(batch->cmdbuf, q->query_pool, q->curr_query, flags);
97 }
98
99 static bool
100 zink_begin_query(struct pipe_context *pctx,
101 struct pipe_query *q)
102 {
103 struct zink_context *ctx = zink_context(pctx);
104 struct zink_query *query = (struct zink_query *)q;
105
106 /* ignore begin_query for timestamps */
107 if (query->type == PIPE_QUERY_TIMESTAMP)
108 return true;
109
110 /* TODO: resetting on begin isn't ideal, as it forces render-pass exit...
111 * should instead reset on creation (if possible?)... Or perhaps maintain
112 * the pool in the batch instead?
113 */
114 struct zink_batch *batch = zink_batch_no_rp(zink_context(pctx));
115 vkCmdResetQueryPool(batch->cmdbuf, query->query_pool, 0, query->curr_query);
116 query->curr_query = 0;
117
118 begin_query(ctx, query);
119 list_addtail(&query->active_list, &ctx->active_queries);
120
121 return true;
122 }
123
124 static void
125 end_query(struct zink_context *ctx, struct zink_query *q)
126 {
127 struct zink_batch *batch = zink_curr_batch(ctx);
128 assert(q->type != PIPE_QUERY_TIMESTAMP);
129 vkCmdEndQuery(batch->cmdbuf, q->query_pool, q->curr_query);
130 if (++q->curr_query == q->num_queries) {
131 assert(0);
132 /* need to reset pool! */
133 }
134 }
135
136 static bool
137 zink_end_query(struct pipe_context *pctx,
138 struct pipe_query *q)
139 {
140 struct zink_context *ctx = zink_context(pctx);
141 struct zink_query *query = (struct zink_query *)q;
142
143 if (query->type == PIPE_QUERY_TIMESTAMP) {
144 assert(query->curr_query == 0);
145 struct zink_batch *batch = zink_curr_batch(ctx);
146 vkCmdWriteTimestamp(batch->cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
147 query->query_pool, 0);
148 } else {
149 end_query(ctx, query);
150 list_delinit(&query->active_list);
151 }
152
153 return true;
154 }
155
156 static bool
157 zink_get_query_result(struct pipe_context *pctx,
158 struct pipe_query *q,
159 bool wait,
160 union pipe_query_result *result)
161 {
162 struct zink_screen *screen = zink_screen(pctx->screen);
163 struct zink_query *query = (struct zink_query *)q;
164 VkQueryResultFlagBits flags = 0;
165
166 if (wait) {
167 struct pipe_fence_handle *fence = NULL;
168 pctx->flush(pctx, &fence, PIPE_FLUSH_HINT_FINISH);
169 if (fence) {
170 pctx->screen->fence_finish(pctx->screen, NULL, fence,
171 PIPE_TIMEOUT_INFINITE);
172 pctx->screen->fence_reference(pctx->screen, &fence, NULL);
173 }
174 flags |= VK_QUERY_RESULT_WAIT_BIT;
175 } else
176 pctx->flush(pctx, NULL, 0);
177
178 if (query->use_64bit)
179 flags |= VK_QUERY_RESULT_64_BIT;
180
181 // TODO: handle curr_query > 100
182 // union pipe_query_result results[100];
183 uint64_t results[100];
184 memset(results, 0, sizeof(results));
185 assert(query->curr_query <= ARRAY_SIZE(results));
186 if (vkGetQueryPoolResults(screen->dev, query->query_pool,
187 0, query->curr_query,
188 sizeof(results),
189 results,
190 sizeof(uint64_t),
191 flags) != VK_SUCCESS)
192 return false;
193
194 util_query_clear_result(result, query->type);
195 for (int i = 0; i < query->curr_query; ++i) {
196 switch (query->type) {
197 case PIPE_QUERY_OCCLUSION_PREDICATE:
198 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
199 case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
200 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
201 case PIPE_QUERY_GPU_FINISHED:
202 result->b |= results[i] != 0;
203 break;
204
205 case PIPE_QUERY_OCCLUSION_COUNTER:
206 result->u64 += results[i];
207 break;
208
209 default:
210 debug_printf("unhangled query type: %s\n",
211 util_str_query_type(query->type, true));
212 unreachable("unexpected query type");
213 }
214 }
215
216 return TRUE;
217 }
218
219 void
220 zink_suspend_queries(struct zink_context *ctx, struct zink_batch *batch)
221 {
222 struct zink_query *query;
223 LIST_FOR_EACH_ENTRY(query, &ctx->active_queries, active_list) {
224 end_query(ctx, query);
225 }
226 }
227
228 void
229 zink_resume_queries(struct zink_context *ctx, struct zink_batch *batch)
230 {
231 struct zink_query *query;
232 LIST_FOR_EACH_ENTRY(query, &ctx->active_queries, active_list) {
233 begin_query(ctx, query);
234 }
235 }
236
237 static void
238 zink_set_active_query_state(struct pipe_context *pctx, bool enable)
239 {
240 struct zink_context *ctx = zink_context(pctx);
241 ctx->queries_disabled = !enable;
242
243 struct zink_batch *batch = zink_curr_batch(ctx);
244 if (ctx->queries_disabled)
245 zink_suspend_queries(ctx, batch);
246 else
247 zink_resume_queries(ctx, batch);
248 }
249
250 void
251 zink_context_query_init(struct pipe_context *pctx)
252 {
253 struct zink_context *ctx = zink_context(pctx);
254 list_inithead(&ctx->active_queries);
255
256 pctx->create_query = zink_create_query;
257 pctx->destroy_query = zink_destroy_query;
258 pctx->begin_query = zink_begin_query;
259 pctx->end_query = zink_end_query;
260 pctx->get_query_result = zink_get_query_result;
261 pctx->set_active_query_state = zink_set_active_query_state;
262 }