1 /*
2 * Copyright © 2021 Collabora Ltd.
3 *
4 * Derived from tu_cmd_buffer.c which is:
5 * Copyright © 2016 Red Hat.
6 * Copyright © 2016 Bas Nieuwenhuizen
7 * Copyright © 2015 Intel Corporation
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28
29 #include "genxml/gen_macros.h"
30
31 #include "panvk_cs.h"
32 #include "panvk_private.h"
33 #include "panfrost-quirks.h"
34
35 #include "pan_blitter.h"
36 #include "pan_cs.h"
37 #include "pan_encoder.h"
38
39 #include "util/rounding.h"
40 #include "util/u_pack_color.h"
41 #include "vk_format.h"
42
43 static void
panvk_cmd_prepare_fragment_job(struct panvk_cmd_buffer * cmdbuf)44 panvk_cmd_prepare_fragment_job(struct panvk_cmd_buffer *cmdbuf)
45 {
46 const struct pan_fb_info *fbinfo = &cmdbuf->state.fb.info;
47 struct panvk_batch *batch = cmdbuf->state.batch;
48 struct panfrost_ptr job_ptr =
49 pan_pool_alloc_desc(&cmdbuf->desc_pool.base, FRAGMENT_JOB);
50
51 GENX(pan_emit_fragment_job)(fbinfo, batch->fb.desc.gpu, job_ptr.cpu),
52 batch->fragment_job = job_ptr.gpu;
53 util_dynarray_append(&batch->jobs, void *, job_ptr.cpu);
54 }
55
56 #if PAN_ARCH == 5
57 void
panvk_per_arch(cmd_get_polygon_list)58 panvk_per_arch(cmd_get_polygon_list)(struct panvk_cmd_buffer *cmdbuf,
59 unsigned width, unsigned height,
60 bool has_draws)
61 {
62 struct panfrost_device *pdev = &cmdbuf->device->physical_device->pdev;
63 struct panvk_batch *batch = cmdbuf->state.batch;
64
65 if (batch->tiler.ctx.midgard.polygon_list)
66 return;
67
68 unsigned size =
69 panfrost_tiler_get_polygon_list_size(pdev, width, height, has_draws);
70 size = util_next_power_of_two(size);
71
72 /* Create the BO as invisible if we can. In the non-hierarchical tiler case,
73 * we need to write the polygon list manually because there's not WRITE_VALUE
74 * job in the chain. */
75 bool init_polygon_list = !has_draws && (pdev->quirks & MIDGARD_NO_HIER_TILING);
76 batch->tiler.ctx.midgard.polygon_list =
77 panfrost_bo_create(pdev, size,
78 init_polygon_list ? 0 : PAN_BO_INVISIBLE,
79 "Polygon list");
80
81
82 if (init_polygon_list) {
83 assert(batch->tiler.ctx.midgard.polygon_list->ptr.cpu);
84 uint32_t *polygon_list_body =
85 batch->tiler.ctx.midgard.polygon_list->ptr.cpu +
86 MALI_MIDGARD_TILER_MINIMUM_HEADER_SIZE;
87 polygon_list_body[0] = 0xa0000000;
88 }
89
90 batch->tiler.ctx.midgard.disable = !has_draws;
91 }
92 #endif
93
94 #if PAN_ARCH <= 5
95 static void
panvk_copy_fb_desc(struct panvk_cmd_buffer * cmdbuf,void * src)96 panvk_copy_fb_desc(struct panvk_cmd_buffer *cmdbuf, void *src)
97 {
98 const struct pan_fb_info *fbinfo = &cmdbuf->state.fb.info;
99 struct panvk_batch *batch = cmdbuf->state.batch;
100 uint32_t size = pan_size(FRAMEBUFFER);
101
102 if (fbinfo->zs.view.zs || fbinfo->zs.view.s)
103 size += pan_size(ZS_CRC_EXTENSION);
104
105 size += MAX2(fbinfo->rt_count, 1) * pan_size(RENDER_TARGET);
106
107 memcpy(batch->fb.desc.cpu, src, size);
108 }
109 #endif
110
111 void
panvk_per_arch(cmd_close_batch)112 panvk_per_arch(cmd_close_batch)(struct panvk_cmd_buffer *cmdbuf)
113 {
114 struct panvk_batch *batch = cmdbuf->state.batch;
115
116 if (!batch)
117 return;
118
119 const struct pan_fb_info *fbinfo = &cmdbuf->state.fb.info;
120 #if PAN_ARCH <= 5
121 uint32_t tmp_fbd[(pan_size(FRAMEBUFFER) +
122 pan_size(ZS_CRC_EXTENSION) +
123 (MAX_RTS * pan_size(RENDER_TARGET))) / 4];
124 #endif
125
126 assert(batch);
127
128 bool clear = fbinfo->zs.clear.z | fbinfo->zs.clear.s;
129 for (unsigned i = 0; i < fbinfo->rt_count; i++)
130 clear |= fbinfo->rts[i].clear;
131
132 if (!clear && !batch->scoreboard.first_job) {
133 if (util_dynarray_num_elements(&batch->event_ops, struct panvk_event_op) == 0) {
134 /* Content-less batch, let's drop it */
135 vk_free(&cmdbuf->pool->alloc, batch);
136 } else {
137 /* Batch has no jobs but is needed for synchronization, let's add a
138 * NULL job so the SUBMIT ioctl doesn't choke on it.
139 */
140 struct panfrost_ptr ptr = pan_pool_alloc_desc(&cmdbuf->desc_pool.base,
141 JOB_HEADER);
142 util_dynarray_append(&batch->jobs, void *, ptr.cpu);
143 panfrost_add_job(&cmdbuf->desc_pool.base, &batch->scoreboard,
144 MALI_JOB_TYPE_NULL, false, false, 0, 0,
145 &ptr, false);
146 list_addtail(&batch->node, &cmdbuf->batches);
147 }
148 cmdbuf->state.batch = NULL;
149 return;
150 }
151
152 struct panfrost_device *pdev = &cmdbuf->device->physical_device->pdev;
153
154 list_addtail(&batch->node, &cmdbuf->batches);
155
156 if (batch->scoreboard.first_tiler) {
157 struct panfrost_ptr preload_jobs[2];
158 unsigned num_preload_jobs =
159 GENX(pan_preload_fb)(&cmdbuf->desc_pool.base, &batch->scoreboard,
160 &cmdbuf->state.fb.info,
161 PAN_ARCH >= 6 ? batch->tls.gpu : batch->fb.desc.gpu,
162 PAN_ARCH >= 6 ? batch->tiler.descs.gpu : 0,
163 preload_jobs);
164 for (unsigned i = 0; i < num_preload_jobs; i++)
165 util_dynarray_append(&batch->jobs, void *, preload_jobs[i].cpu);
166 }
167
168 if (batch->tlsinfo.tls.size) {
169 batch->tlsinfo.tls.ptr =
170 pan_pool_alloc_aligned(&cmdbuf->tls_pool.base, batch->tlsinfo.tls.size, 4096).gpu;
171 }
172
173 if (batch->tlsinfo.wls.size) {
174 assert(batch->wls_total_size);
175 batch->tlsinfo.wls.ptr =
176 pan_pool_alloc_aligned(&cmdbuf->tls_pool.base, batch->wls_total_size, 4096).gpu;
177 }
178
179 if ((PAN_ARCH >= 6 || !batch->fb.desc.cpu) && batch->tls.cpu)
180 GENX(pan_emit_tls)(&batch->tlsinfo, batch->tls.cpu);
181
182 if (batch->fb.desc.cpu) {
183 #if PAN_ARCH == 5
184 panvk_per_arch(cmd_get_polygon_list)(cmdbuf,
185 fbinfo->width,
186 fbinfo->height,
187 false);
188
189 mali_ptr polygon_list =
190 batch->tiler.ctx.midgard.polygon_list->ptr.gpu;
191 struct panfrost_ptr writeval_job =
192 panfrost_scoreboard_initialize_tiler(&cmdbuf->desc_pool.base,
193 &batch->scoreboard,
194 polygon_list);
195 if (writeval_job.cpu)
196 util_dynarray_append(&batch->jobs, void *, writeval_job.cpu);
197 #endif
198
199 #if PAN_ARCH <= 5
200 void *fbd = tmp_fbd;
201 #else
202 void *fbd = batch->fb.desc.cpu;
203 #endif
204
205 batch->fb.desc.gpu |=
206 GENX(pan_emit_fbd)(pdev, &cmdbuf->state.fb.info, &batch->tlsinfo,
207 &batch->tiler.ctx, fbd);
208
209 #if PAN_ARCH <= 5
210 panvk_copy_fb_desc(cmdbuf, tmp_fbd);
211 memcpy(batch->tiler.templ,
212 pan_section_ptr(fbd, FRAMEBUFFER, TILER),
213 pan_size(TILER_CONTEXT));
214 #endif
215
216 panvk_cmd_prepare_fragment_job(cmdbuf);
217 }
218
219 cmdbuf->state.batch = NULL;
220 }
221
222 void
panvk_per_arch(CmdNextSubpass2)223 panvk_per_arch(CmdNextSubpass2)(VkCommandBuffer commandBuffer,
224 const VkSubpassBeginInfo *pSubpassBeginInfo,
225 const VkSubpassEndInfo *pSubpassEndInfo)
226 {
227 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
228
229 panvk_per_arch(cmd_close_batch)(cmdbuf);
230
231 cmdbuf->state.subpass++;
232 panvk_cmd_fb_info_set_subpass(cmdbuf);
233 panvk_cmd_open_batch(cmdbuf);
234 }
235
236 void
panvk_per_arch(CmdNextSubpass)237 panvk_per_arch(CmdNextSubpass)(VkCommandBuffer cmd, VkSubpassContents contents)
238 {
239 VkSubpassBeginInfo binfo = {
240 .sType = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO,
241 .contents = contents
242 };
243 VkSubpassEndInfo einfo = {
244 .sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO,
245 };
246
247 panvk_per_arch(CmdNextSubpass2)(cmd, &binfo, &einfo);
248 }
249
250 void
panvk_per_arch(cmd_alloc_fb_desc)251 panvk_per_arch(cmd_alloc_fb_desc)(struct panvk_cmd_buffer *cmdbuf)
252 {
253 struct panvk_batch *batch = cmdbuf->state.batch;
254
255 if (batch->fb.desc.gpu)
256 return;
257
258 const struct pan_fb_info *fbinfo = &cmdbuf->state.fb.info;
259 bool has_zs_ext = fbinfo->zs.view.zs || fbinfo->zs.view.s;
260 unsigned tags = MALI_FBD_TAG_IS_MFBD;
261
262 batch->fb.info = cmdbuf->state.framebuffer;
263 batch->fb.desc =
264 pan_pool_alloc_desc_aggregate(&cmdbuf->desc_pool.base,
265 PAN_DESC(FRAMEBUFFER),
266 PAN_DESC_ARRAY(has_zs_ext ? 1 : 0, ZS_CRC_EXTENSION),
267 PAN_DESC_ARRAY(MAX2(fbinfo->rt_count, 1), RENDER_TARGET));
268
269 /* Tag the pointer */
270 batch->fb.desc.gpu |= tags;
271
272 #if PAN_ARCH >= 6
273 memset(&cmdbuf->state.fb.info.bifrost.pre_post.dcds, 0,
274 sizeof(cmdbuf->state.fb.info.bifrost.pre_post.dcds));
275 #endif
276 }
277
278 void
panvk_per_arch(cmd_alloc_tls_desc)279 panvk_per_arch(cmd_alloc_tls_desc)(struct panvk_cmd_buffer *cmdbuf, bool gfx)
280 {
281 struct panvk_batch *batch = cmdbuf->state.batch;
282
283 assert(batch);
284 if (batch->tls.gpu)
285 return;
286
287 if (PAN_ARCH == 5 && gfx) {
288 panvk_per_arch(cmd_alloc_fb_desc)(cmdbuf);
289 batch->tls = batch->fb.desc;
290 batch->tls.gpu &= ~63ULL;
291 } else {
292 batch->tls =
293 pan_pool_alloc_desc(&cmdbuf->desc_pool.base, LOCAL_STORAGE);
294 }
295 }
296
297 static void
panvk_cmd_upload_sysval(struct panvk_cmd_buffer * cmdbuf,unsigned id,union panvk_sysval_data * data)298 panvk_cmd_upload_sysval(struct panvk_cmd_buffer *cmdbuf,
299 unsigned id, union panvk_sysval_data *data)
300 {
301 switch (PAN_SYSVAL_TYPE(id)) {
302 case PAN_SYSVAL_VIEWPORT_SCALE:
303 panvk_sysval_upload_viewport_scale(&cmdbuf->state.viewport, data);
304 break;
305 case PAN_SYSVAL_VIEWPORT_OFFSET:
306 panvk_sysval_upload_viewport_offset(&cmdbuf->state.viewport, data);
307 break;
308 case PAN_SYSVAL_VERTEX_INSTANCE_OFFSETS:
309 /* TODO: support base_{vertex,instance} */
310 data->u32[0] = data->u32[1] = data->u32[2] = 0;
311 break;
312 case PAN_SYSVAL_BLEND_CONSTANTS:
313 memcpy(data->f32, cmdbuf->state.blend.constants, sizeof(data->f32));
314 break;
315 default:
316 unreachable("Invalid static sysval");
317 }
318 }
319
320 static void
panvk_cmd_prepare_sysvals(struct panvk_cmd_buffer * cmdbuf,struct panvk_cmd_bind_point_state * bind_point_state)321 panvk_cmd_prepare_sysvals(struct panvk_cmd_buffer *cmdbuf,
322 struct panvk_cmd_bind_point_state *bind_point_state)
323 {
324 struct panvk_descriptor_state *desc_state = &bind_point_state->desc_state;
325 const struct panvk_pipeline *pipeline = bind_point_state->pipeline;
326
327 if (!pipeline->num_sysvals)
328 return;
329
330 for (unsigned i = 0; i < ARRAY_SIZE(desc_state->sysvals); i++) {
331 unsigned sysval_count = pipeline->sysvals[i].ids.sysval_count;
332 if (!sysval_count || pipeline->sysvals[i].ubo ||
333 (desc_state->sysvals[i] &&
334 !(cmdbuf->state.dirty & pipeline->sysvals[i].dirty_mask)))
335 continue;
336
337 struct panfrost_ptr sysvals =
338 pan_pool_alloc_aligned(&cmdbuf->desc_pool.base, sysval_count * 16, 16);
339 union panvk_sysval_data *data = sysvals.cpu;
340
341 for (unsigned s = 0; s < pipeline->sysvals[i].ids.sysval_count; s++) {
342 panvk_cmd_upload_sysval(cmdbuf, pipeline->sysvals[i].ids.sysvals[s],
343 &data[s]);
344 }
345
346 desc_state->sysvals[i] = sysvals.gpu;
347 }
348 }
349
350 static void
panvk_cmd_prepare_ubos(struct panvk_cmd_buffer * cmdbuf,struct panvk_cmd_bind_point_state * bind_point_state)351 panvk_cmd_prepare_ubos(struct panvk_cmd_buffer *cmdbuf,
352 struct panvk_cmd_bind_point_state *bind_point_state)
353 {
354 struct panvk_descriptor_state *desc_state = &bind_point_state->desc_state;
355 const struct panvk_pipeline *pipeline = bind_point_state->pipeline;
356
357 if (!pipeline->num_ubos || desc_state->ubos)
358 return;
359
360 panvk_cmd_prepare_sysvals(cmdbuf, bind_point_state);
361
362 struct panfrost_ptr ubos =
363 pan_pool_alloc_desc_array(&cmdbuf->desc_pool.base,
364 pipeline->num_ubos,
365 UNIFORM_BUFFER);
366
367 panvk_per_arch(emit_ubos)(pipeline, desc_state, ubos.cpu);
368
369 desc_state->ubos = ubos.gpu;
370 }
371
372 static void
panvk_cmd_prepare_textures(struct panvk_cmd_buffer * cmdbuf,struct panvk_cmd_bind_point_state * bind_point_state)373 panvk_cmd_prepare_textures(struct panvk_cmd_buffer *cmdbuf,
374 struct panvk_cmd_bind_point_state *bind_point_state)
375 {
376 struct panvk_descriptor_state *desc_state = &bind_point_state->desc_state;
377 const struct panvk_pipeline *pipeline = bind_point_state->pipeline;
378 unsigned num_textures = pipeline->layout->num_textures;
379
380 if (!num_textures || desc_state->textures)
381 return;
382
383 unsigned tex_entry_size = PAN_ARCH >= 6 ?
384 pan_size(TEXTURE) :
385 sizeof(mali_ptr);
386 struct panfrost_ptr textures =
387 pan_pool_alloc_aligned(&cmdbuf->desc_pool.base,
388 num_textures * tex_entry_size,
389 tex_entry_size);
390
391 void *texture = textures.cpu;
392
393 for (unsigned i = 0; i < ARRAY_SIZE(desc_state->sets); i++) {
394 if (!desc_state->sets[i].set) continue;
395
396 memcpy(texture,
397 desc_state->sets[i].set->textures,
398 desc_state->sets[i].set->layout->num_textures *
399 tex_entry_size);
400
401 texture += desc_state->sets[i].set->layout->num_textures *
402 tex_entry_size;
403 }
404
405 desc_state->textures = textures.gpu;
406 }
407
408 static void
panvk_cmd_prepare_samplers(struct panvk_cmd_buffer * cmdbuf,struct panvk_cmd_bind_point_state * bind_point_state)409 panvk_cmd_prepare_samplers(struct panvk_cmd_buffer *cmdbuf,
410 struct panvk_cmd_bind_point_state *bind_point_state)
411 {
412 struct panvk_descriptor_state *desc_state = &bind_point_state->desc_state;
413 const struct panvk_pipeline *pipeline = bind_point_state->pipeline;
414 unsigned num_samplers = pipeline->layout->num_samplers;
415
416 if (!num_samplers || desc_state->samplers)
417 return;
418
419 struct panfrost_ptr samplers =
420 pan_pool_alloc_desc_array(&cmdbuf->desc_pool.base,
421 num_samplers,
422 SAMPLER);
423
424 void *sampler = samplers.cpu;
425
426 for (unsigned i = 0; i < ARRAY_SIZE(desc_state->sets); i++) {
427 if (!desc_state->sets[i].set) continue;
428
429 memcpy(sampler,
430 desc_state->sets[i].set->samplers,
431 desc_state->sets[i].set->layout->num_samplers *
432 pan_size(SAMPLER));
433
434 sampler += desc_state->sets[i].set->layout->num_samplers;
435 }
436
437 desc_state->samplers = samplers.gpu;
438 }
439
440 static void
panvk_draw_prepare_fs_rsd(struct panvk_cmd_buffer * cmdbuf,struct panvk_draw_info * draw)441 panvk_draw_prepare_fs_rsd(struct panvk_cmd_buffer *cmdbuf,
442 struct panvk_draw_info *draw)
443 {
444 const struct panvk_pipeline *pipeline =
445 panvk_cmd_get_pipeline(cmdbuf, GRAPHICS);
446
447 if (!pipeline->fs.dynamic_rsd) {
448 draw->fs_rsd = pipeline->rsds[MESA_SHADER_FRAGMENT];
449 return;
450 }
451
452 if (!cmdbuf->state.fs_rsd) {
453 struct panfrost_ptr rsd =
454 pan_pool_alloc_desc_aggregate(&cmdbuf->desc_pool.base,
455 PAN_DESC(RENDERER_STATE),
456 PAN_DESC_ARRAY(pipeline->blend.state.rt_count,
457 BLEND));
458
459 struct mali_renderer_state_packed rsd_dyn;
460 struct mali_renderer_state_packed *rsd_templ =
461 (struct mali_renderer_state_packed *)&pipeline->fs.rsd_template;
462
463 STATIC_ASSERT(sizeof(pipeline->fs.rsd_template) >= sizeof(*rsd_templ));
464
465 panvk_per_arch(emit_dyn_fs_rsd)(pipeline, &cmdbuf->state, &rsd_dyn);
466 pan_merge(rsd_dyn, (*rsd_templ), RENDERER_STATE);
467 memcpy(rsd.cpu, &rsd_dyn, sizeof(rsd_dyn));
468
469 void *bd = rsd.cpu + pan_size(RENDERER_STATE);
470 for (unsigned i = 0; i < pipeline->blend.state.rt_count; i++) {
471 if (pipeline->blend.constant[i].index != ~0) {
472 struct mali_blend_packed bd_dyn;
473 struct mali_blend_packed *bd_templ =
474 (struct mali_blend_packed *)&pipeline->blend.bd_template[i];
475
476 STATIC_ASSERT(sizeof(pipeline->blend.bd_template[0]) >= sizeof(*bd_templ));
477 panvk_per_arch(emit_blend_constant)(cmdbuf->device, pipeline, i,
478 cmdbuf->state.blend.constants,
479 &bd_dyn);
480 pan_merge(bd_dyn, (*bd_templ), BLEND);
481 memcpy(bd, &bd_dyn, sizeof(bd_dyn));
482 }
483 bd += pan_size(BLEND);
484 }
485
486 cmdbuf->state.fs_rsd = rsd.gpu;
487 }
488
489 draw->fs_rsd = cmdbuf->state.fs_rsd;
490 }
491
492 #if PAN_ARCH >= 6
493 void
panvk_per_arch(cmd_get_tiler_context)494 panvk_per_arch(cmd_get_tiler_context)(struct panvk_cmd_buffer *cmdbuf,
495 unsigned width, unsigned height)
496 {
497 struct panvk_batch *batch = cmdbuf->state.batch;
498
499 if (batch->tiler.descs.cpu)
500 return;
501
502 batch->tiler.descs =
503 pan_pool_alloc_desc_aggregate(&cmdbuf->desc_pool.base,
504 PAN_DESC(TILER_CONTEXT),
505 PAN_DESC(TILER_HEAP));
506 STATIC_ASSERT(sizeof(batch->tiler.templ) >=
507 pan_size(TILER_CONTEXT) + pan_size(TILER_HEAP));
508
509 struct panfrost_ptr desc = {
510 .gpu = batch->tiler.descs.gpu,
511 .cpu = batch->tiler.templ,
512 };
513
514 panvk_per_arch(emit_tiler_context)(cmdbuf->device, width, height, &desc);
515 memcpy(batch->tiler.descs.cpu, batch->tiler.templ,
516 pan_size(TILER_CONTEXT) + pan_size(TILER_HEAP));
517 batch->tiler.ctx.bifrost = batch->tiler.descs.gpu;
518 }
519 #endif
520
521 void
panvk_per_arch(cmd_prepare_tiler_context)522 panvk_per_arch(cmd_prepare_tiler_context)(struct panvk_cmd_buffer *cmdbuf)
523 {
524 const struct pan_fb_info *fbinfo = &cmdbuf->state.fb.info;
525
526 #if PAN_ARCH == 5
527 panvk_per_arch(cmd_get_polygon_list)(cmdbuf,
528 fbinfo->width,
529 fbinfo->height,
530 true);
531 #else
532 panvk_per_arch(cmd_get_tiler_context)(cmdbuf,
533 fbinfo->width,
534 fbinfo->height);
535 #endif
536 }
537
538 static void
panvk_draw_prepare_tiler_context(struct panvk_cmd_buffer * cmdbuf,struct panvk_draw_info * draw)539 panvk_draw_prepare_tiler_context(struct panvk_cmd_buffer *cmdbuf,
540 struct panvk_draw_info *draw)
541 {
542 struct panvk_batch *batch = cmdbuf->state.batch;
543
544 panvk_per_arch(cmd_prepare_tiler_context)(cmdbuf);
545 draw->tiler_ctx = &batch->tiler.ctx;
546 }
547
548 static void
panvk_draw_prepare_varyings(struct panvk_cmd_buffer * cmdbuf,struct panvk_draw_info * draw)549 panvk_draw_prepare_varyings(struct panvk_cmd_buffer *cmdbuf,
550 struct panvk_draw_info *draw)
551 {
552 const struct panvk_pipeline *pipeline = panvk_cmd_get_pipeline(cmdbuf, GRAPHICS);
553 struct panvk_varyings_info *varyings = &cmdbuf->state.varyings;
554
555 panvk_varyings_alloc(varyings, &cmdbuf->varying_pool.base,
556 draw->vertex_count);
557
558 unsigned buf_count = panvk_varyings_buf_count(varyings);
559 struct panfrost_ptr bufs =
560 pan_pool_alloc_desc_array(&cmdbuf->desc_pool.base,
561 buf_count, ATTRIBUTE_BUFFER);
562
563 panvk_per_arch(emit_varying_bufs)(varyings, bufs.cpu);
564 if (BITSET_TEST(varyings->active, VARYING_SLOT_POS)) {
565 draw->position = varyings->buf[varyings->varying[VARYING_SLOT_POS].buf].address +
566 varyings->varying[VARYING_SLOT_POS].offset;
567 }
568
569 if (BITSET_TEST(varyings->active, VARYING_SLOT_PSIZ)) {
570 draw->psiz = varyings->buf[varyings->varying[VARYING_SLOT_PSIZ].buf].address +
571 varyings->varying[VARYING_SLOT_POS].offset;
572 } else if (pipeline->ia.topology == MALI_DRAW_MODE_LINES ||
573 pipeline->ia.topology == MALI_DRAW_MODE_LINE_STRIP ||
574 pipeline->ia.topology == MALI_DRAW_MODE_LINE_LOOP) {
575 draw->line_width = pipeline->dynamic_state_mask & PANVK_DYNAMIC_LINE_WIDTH ?
576 cmdbuf->state.rast.line_width : pipeline->rast.line_width;
577 } else {
578 draw->line_width = 1.0f;
579 }
580 draw->varying_bufs = bufs.gpu;
581
582 for (unsigned s = 0; s < MESA_SHADER_STAGES; s++) {
583 if (!varyings->stage[s].count) continue;
584
585 struct panfrost_ptr attribs =
586 pan_pool_alloc_desc_array(&cmdbuf->desc_pool.base,
587 varyings->stage[s].count,
588 ATTRIBUTE);
589
590 panvk_per_arch(emit_varyings)(cmdbuf->device, varyings, s, attribs.cpu);
591 draw->stages[s].varyings = attribs.gpu;
592 }
593 }
594
595 static void
panvk_draw_prepare_attributes(struct panvk_cmd_buffer * cmdbuf,struct panvk_draw_info * draw)596 panvk_draw_prepare_attributes(struct panvk_cmd_buffer *cmdbuf,
597 struct panvk_draw_info *draw)
598 {
599 const struct panvk_pipeline *pipeline = panvk_cmd_get_pipeline(cmdbuf, GRAPHICS);
600
601 /* TODO: images */
602 if (!pipeline->attribs.buf_count)
603 return;
604
605 if (cmdbuf->state.vb.attribs) {
606 draw->stages[MESA_SHADER_VERTEX].attributes = cmdbuf->state.vb.attribs;
607 draw->attribute_bufs = cmdbuf->state.vb.attrib_bufs;
608 return;
609 }
610
611 unsigned buf_count = pipeline->attribs.buf_count +
612 (PAN_ARCH >= 6 ? 1 : 0);
613 struct panfrost_ptr bufs =
614 pan_pool_alloc_desc_array(&cmdbuf->desc_pool.base,
615 buf_count * 2, ATTRIBUTE_BUFFER);
616
617 panvk_per_arch(emit_attrib_bufs)(&pipeline->attribs,
618 cmdbuf->state.vb.bufs,
619 cmdbuf->state.vb.count,
620 draw, bufs.cpu);
621 cmdbuf->state.vb.attrib_bufs = bufs.gpu;
622
623 struct panfrost_ptr attribs =
624 pan_pool_alloc_desc_array(&cmdbuf->desc_pool.base,
625 pipeline->attribs.attrib_count,
626 ATTRIBUTE);
627
628 panvk_per_arch(emit_attribs)(cmdbuf->device, &pipeline->attribs,
629 cmdbuf->state.vb.bufs, cmdbuf->state.vb.count,
630 attribs.cpu);
631 cmdbuf->state.vb.attribs = attribs.gpu;
632 draw->stages[MESA_SHADER_VERTEX].attributes = cmdbuf->state.vb.attribs;
633 draw->attribute_bufs = cmdbuf->state.vb.attrib_bufs;
634 }
635
636 static void
panvk_draw_prepare_viewport(struct panvk_cmd_buffer * cmdbuf,struct panvk_draw_info * draw)637 panvk_draw_prepare_viewport(struct panvk_cmd_buffer *cmdbuf,
638 struct panvk_draw_info *draw)
639 {
640 const struct panvk_pipeline *pipeline = panvk_cmd_get_pipeline(cmdbuf, GRAPHICS);
641
642 if (pipeline->vpd) {
643 draw->viewport = pipeline->vpd;
644 } else if (cmdbuf->state.vpd) {
645 draw->viewport = cmdbuf->state.vpd;
646 } else {
647 struct panfrost_ptr vp =
648 pan_pool_alloc_desc(&cmdbuf->desc_pool.base, VIEWPORT);
649
650 const VkViewport *viewport =
651 pipeline->dynamic_state_mask & PANVK_DYNAMIC_VIEWPORT ?
652 &cmdbuf->state.viewport : &pipeline->viewport;
653 const VkRect2D *scissor =
654 pipeline->dynamic_state_mask & PANVK_DYNAMIC_SCISSOR ?
655 &cmdbuf->state.scissor : &pipeline->scissor;
656
657 panvk_per_arch(emit_viewport)(viewport, scissor, vp.cpu);
658 draw->viewport = cmdbuf->state.vpd = vp.gpu;
659 }
660 }
661
662 static void
panvk_draw_prepare_vertex_job(struct panvk_cmd_buffer * cmdbuf,struct panvk_draw_info * draw)663 panvk_draw_prepare_vertex_job(struct panvk_cmd_buffer *cmdbuf,
664 struct panvk_draw_info *draw)
665 {
666 const struct panvk_pipeline *pipeline = panvk_cmd_get_pipeline(cmdbuf, GRAPHICS);
667 struct panvk_batch *batch = cmdbuf->state.batch;
668 struct panfrost_ptr ptr =
669 pan_pool_alloc_desc(&cmdbuf->desc_pool.base, COMPUTE_JOB);
670
671 util_dynarray_append(&batch->jobs, void *, ptr.cpu);
672 draw->jobs.vertex = ptr;
673 panvk_per_arch(emit_vertex_job)(pipeline, draw, ptr.cpu);
674 }
675
676 static void
panvk_draw_prepare_tiler_job(struct panvk_cmd_buffer * cmdbuf,struct panvk_draw_info * draw)677 panvk_draw_prepare_tiler_job(struct panvk_cmd_buffer *cmdbuf,
678 struct panvk_draw_info *draw)
679 {
680 const struct panvk_pipeline *pipeline = panvk_cmd_get_pipeline(cmdbuf, GRAPHICS);
681 struct panvk_batch *batch = cmdbuf->state.batch;
682 struct panfrost_ptr ptr =
683 pan_pool_alloc_desc(&cmdbuf->desc_pool.base, TILER_JOB);
684
685 util_dynarray_append(&batch->jobs, void *, ptr.cpu);
686 draw->jobs.tiler = ptr;
687 panvk_per_arch(emit_tiler_job)(pipeline, draw, ptr.cpu);
688 }
689
690 void
panvk_per_arch(CmdDraw)691 panvk_per_arch(CmdDraw)(VkCommandBuffer commandBuffer,
692 uint32_t vertexCount,
693 uint32_t instanceCount,
694 uint32_t firstVertex,
695 uint32_t firstInstance)
696 {
697 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
698
699 struct panvk_batch *batch = cmdbuf->state.batch;
700 struct panvk_cmd_bind_point_state *bind_point_state =
701 panvk_cmd_get_bind_point_state(cmdbuf, GRAPHICS);
702 const struct panvk_pipeline *pipeline =
703 panvk_cmd_get_pipeline(cmdbuf, GRAPHICS);
704
705 /* There are only 16 bits in the descriptor for the job ID, make sure all
706 * the 3 (2 in Bifrost) jobs in this draw are in the same batch.
707 */
708 if (batch->scoreboard.job_index >= (UINT16_MAX - 3)) {
709 panvk_per_arch(cmd_close_batch)(cmdbuf);
710 panvk_cmd_preload_fb_after_batch_split(cmdbuf);
711 batch = panvk_cmd_open_batch(cmdbuf);
712 }
713
714 if (pipeline->fs.required)
715 panvk_per_arch(cmd_alloc_fb_desc)(cmdbuf);
716
717 panvk_per_arch(cmd_alloc_tls_desc)(cmdbuf, true);
718 panvk_cmd_prepare_ubos(cmdbuf, bind_point_state);
719 panvk_cmd_prepare_textures(cmdbuf, bind_point_state);
720 panvk_cmd_prepare_samplers(cmdbuf, bind_point_state);
721
722 /* TODO: indexed draws */
723 struct panvk_descriptor_state *desc_state =
724 panvk_cmd_get_desc_state(cmdbuf, GRAPHICS);
725
726 struct panvk_draw_info draw = {
727 .first_vertex = firstVertex,
728 .vertex_count = vertexCount,
729 .first_instance = firstInstance,
730 .instance_count = instanceCount,
731 .padded_vertex_count = panfrost_padded_vertex_count(vertexCount),
732 .offset_start = firstVertex,
733 .tls = batch->tls.gpu,
734 .fb = batch->fb.desc.gpu,
735 .ubos = desc_state->ubos,
736 .textures = desc_state->textures,
737 .samplers = desc_state->samplers,
738 };
739
740 STATIC_ASSERT(sizeof(draw.invocation) >= sizeof(struct mali_invocation_packed));
741 panfrost_pack_work_groups_compute((struct mali_invocation_packed *)&draw.invocation,
742 1, vertexCount, instanceCount, 1, 1, 1, true, false);
743 panvk_draw_prepare_fs_rsd(cmdbuf, &draw);
744 panvk_draw_prepare_varyings(cmdbuf, &draw);
745 panvk_draw_prepare_attributes(cmdbuf, &draw);
746 panvk_draw_prepare_viewport(cmdbuf, &draw);
747 panvk_draw_prepare_tiler_context(cmdbuf, &draw);
748 panvk_draw_prepare_vertex_job(cmdbuf, &draw);
749 panvk_draw_prepare_tiler_job(cmdbuf, &draw);
750 batch->tlsinfo.tls.size = MAX2(pipeline->tls_size, batch->tlsinfo.tls.size);
751 assert(!pipeline->wls_size);
752
753 unsigned vjob_id =
754 panfrost_add_job(&cmdbuf->desc_pool.base, &batch->scoreboard,
755 MALI_JOB_TYPE_VERTEX, false, false, 0, 0,
756 &draw.jobs.vertex, false);
757
758 if (pipeline->fs.required) {
759 panfrost_add_job(&cmdbuf->desc_pool.base, &batch->scoreboard,
760 MALI_JOB_TYPE_TILER, false, false, vjob_id, 0,
761 &draw.jobs.tiler, false);
762 }
763
764 /* Clear the dirty flags all at once */
765 cmdbuf->state.dirty = 0;
766 }
767
768 VkResult
panvk_per_arch(EndCommandBuffer)769 panvk_per_arch(EndCommandBuffer)(VkCommandBuffer commandBuffer)
770 {
771 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
772
773 panvk_per_arch(cmd_close_batch)(cmdbuf);
774 cmdbuf->status = PANVK_CMD_BUFFER_STATUS_EXECUTABLE;
775
776 return cmdbuf->record_result;
777 }
778
779 void
panvk_per_arch(CmdEndRenderPass2)780 panvk_per_arch(CmdEndRenderPass2)(VkCommandBuffer commandBuffer,
781 const VkSubpassEndInfoKHR *pSubpassEndInfo)
782 {
783 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
784
785 panvk_per_arch(cmd_close_batch)(cmdbuf);
786 vk_free(&cmdbuf->pool->alloc, cmdbuf->state.clear);
787 cmdbuf->state.batch = NULL;
788 cmdbuf->state.pass = NULL;
789 cmdbuf->state.subpass = NULL;
790 cmdbuf->state.framebuffer = NULL;
791 cmdbuf->state.clear = NULL;
792 }
793
794 void
panvk_per_arch(CmdEndRenderPass)795 panvk_per_arch(CmdEndRenderPass)(VkCommandBuffer cmd)
796 {
797 VkSubpassEndInfoKHR einfo = {
798 .sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO,
799 };
800
801 panvk_per_arch(CmdEndRenderPass2)(cmd, &einfo);
802 }
803
804
805 void
panvk_per_arch(CmdPipelineBarrier)806 panvk_per_arch(CmdPipelineBarrier)(VkCommandBuffer commandBuffer,
807 VkPipelineStageFlags srcStageMask,
808 VkPipelineStageFlags destStageMask,
809 VkDependencyFlags dependencyFlags,
810 uint32_t memoryBarrierCount,
811 const VkMemoryBarrier *pMemoryBarriers,
812 uint32_t bufferMemoryBarrierCount,
813 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
814 uint32_t imageMemoryBarrierCount,
815 const VkImageMemoryBarrier *pImageMemoryBarriers)
816 {
817 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
818
819 /* Caches are flushed/invalidated at batch boundaries for now, nothing to do
820 * for memory barriers assuming we implement barriers with the creation of a
821 * new batch.
822 * FIXME: We can probably do better with a CacheFlush job that has the
823 * barrier flag set to true.
824 */
825 if (cmdbuf->state.batch) {
826 panvk_per_arch(cmd_close_batch)(cmdbuf);
827 panvk_cmd_preload_fb_after_batch_split(cmdbuf);
828 panvk_cmd_open_batch(cmdbuf);
829 }
830 }
831
832 static void
panvk_add_set_event_operation(struct panvk_cmd_buffer * cmdbuf,struct panvk_event * event,enum panvk_event_op_type type)833 panvk_add_set_event_operation(struct panvk_cmd_buffer *cmdbuf,
834 struct panvk_event *event,
835 enum panvk_event_op_type type)
836 {
837 struct panvk_event_op op = {
838 .type = type,
839 .event = event,
840 };
841
842 if (cmdbuf->state.batch == NULL) {
843 /* No open batch, let's create a new one so this operation happens in
844 * the right order.
845 */
846 panvk_cmd_open_batch(cmdbuf);
847 util_dynarray_append(&cmdbuf->state.batch->event_ops,
848 struct panvk_event_op,
849 op);
850 panvk_per_arch(cmd_close_batch)(cmdbuf);
851 } else {
852 /* Let's close the current batch so the operation executes before any
853 * future commands.
854 */
855 util_dynarray_append(&cmdbuf->state.batch->event_ops,
856 struct panvk_event_op,
857 op);
858 panvk_per_arch(cmd_close_batch)(cmdbuf);
859 panvk_cmd_preload_fb_after_batch_split(cmdbuf);
860 panvk_cmd_open_batch(cmdbuf);
861 }
862 }
863
864 static void
panvk_add_wait_event_operation(struct panvk_cmd_buffer * cmdbuf,struct panvk_event * event)865 panvk_add_wait_event_operation(struct panvk_cmd_buffer *cmdbuf,
866 struct panvk_event *event)
867 {
868 struct panvk_event_op op = {
869 .type = PANVK_EVENT_OP_WAIT,
870 .event = event,
871 };
872
873 if (cmdbuf->state.batch == NULL) {
874 /* No open batch, let's create a new one and have it wait for this event. */
875 panvk_cmd_open_batch(cmdbuf);
876 util_dynarray_append(&cmdbuf->state.batch->event_ops,
877 struct panvk_event_op,
878 op);
879 } else {
880 /* Let's close the current batch so any future commands wait on the
881 * event signal operation.
882 */
883 if (cmdbuf->state.batch->fragment_job ||
884 cmdbuf->state.batch->scoreboard.first_job) {
885 panvk_per_arch(cmd_close_batch)(cmdbuf);
886 panvk_cmd_preload_fb_after_batch_split(cmdbuf);
887 panvk_cmd_open_batch(cmdbuf);
888 }
889 util_dynarray_append(&cmdbuf->state.batch->event_ops,
890 struct panvk_event_op,
891 op);
892 }
893 }
894
895 void
panvk_per_arch(CmdSetEvent)896 panvk_per_arch(CmdSetEvent)(VkCommandBuffer commandBuffer,
897 VkEvent _event,
898 VkPipelineStageFlags stageMask)
899 {
900 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
901 VK_FROM_HANDLE(panvk_event, event, _event);
902
903 /* vkCmdSetEvent cannot be called inside a render pass */
904 assert(cmdbuf->state.pass == NULL);
905
906 panvk_add_set_event_operation(cmdbuf, event, PANVK_EVENT_OP_SET);
907 }
908
909 void
panvk_per_arch(CmdResetEvent)910 panvk_per_arch(CmdResetEvent)(VkCommandBuffer commandBuffer,
911 VkEvent _event,
912 VkPipelineStageFlags stageMask)
913 {
914 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
915 VK_FROM_HANDLE(panvk_event, event, _event);
916
917 /* vkCmdResetEvent cannot be called inside a render pass */
918 assert(cmdbuf->state.pass == NULL);
919
920 panvk_add_set_event_operation(cmdbuf, event, PANVK_EVENT_OP_RESET);
921 }
922
923 void
panvk_per_arch(CmdWaitEvents)924 panvk_per_arch(CmdWaitEvents)(VkCommandBuffer commandBuffer,
925 uint32_t eventCount,
926 const VkEvent *pEvents,
927 VkPipelineStageFlags srcStageMask,
928 VkPipelineStageFlags dstStageMask,
929 uint32_t memoryBarrierCount,
930 const VkMemoryBarrier *pMemoryBarriers,
931 uint32_t bufferMemoryBarrierCount,
932 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
933 uint32_t imageMemoryBarrierCount,
934 const VkImageMemoryBarrier *pImageMemoryBarriers)
935 {
936 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
937
938 assert(eventCount > 0);
939
940 for (uint32_t i = 0; i < eventCount; i++) {
941 VK_FROM_HANDLE(panvk_event, event, pEvents[i]);
942 panvk_add_wait_event_operation(cmdbuf, event);
943 }
944 }
945
946 static VkResult
panvk_reset_cmdbuf(struct panvk_cmd_buffer * cmdbuf)947 panvk_reset_cmdbuf(struct panvk_cmd_buffer *cmdbuf)
948 {
949 vk_command_buffer_reset(&cmdbuf->vk);
950
951 cmdbuf->record_result = VK_SUCCESS;
952
953 list_for_each_entry_safe(struct panvk_batch, batch, &cmdbuf->batches, node) {
954 list_del(&batch->node);
955 util_dynarray_fini(&batch->jobs);
956 #if PAN_ARCH <= 5
957 panfrost_bo_unreference(batch->tiler.ctx.midgard.polygon_list);
958 #endif
959
960 util_dynarray_fini(&batch->event_ops);
961
962 vk_free(&cmdbuf->pool->alloc, batch);
963 }
964
965 panvk_pool_reset(&cmdbuf->desc_pool);
966 panvk_pool_reset(&cmdbuf->tls_pool);
967 panvk_pool_reset(&cmdbuf->varying_pool);
968 cmdbuf->status = PANVK_CMD_BUFFER_STATUS_INITIAL;
969
970 for (unsigned i = 0; i < MAX_BIND_POINTS; i++)
971 memset(&cmdbuf->bind_points[i].desc_state.sets, 0, sizeof(cmdbuf->bind_points[0].desc_state.sets));
972
973 return cmdbuf->record_result;
974 }
975
976 static void
panvk_destroy_cmdbuf(struct panvk_cmd_buffer * cmdbuf)977 panvk_destroy_cmdbuf(struct panvk_cmd_buffer *cmdbuf)
978 {
979 struct panvk_device *device = cmdbuf->device;
980
981 list_del(&cmdbuf->pool_link);
982
983 list_for_each_entry_safe(struct panvk_batch, batch, &cmdbuf->batches, node) {
984 list_del(&batch->node);
985 util_dynarray_fini(&batch->jobs);
986 #if PAN_ARCH <= 5
987 panfrost_bo_unreference(batch->tiler.ctx.midgard.polygon_list);
988 #endif
989
990 util_dynarray_fini(&batch->event_ops);
991
992 vk_free(&cmdbuf->pool->alloc, batch);
993 }
994
995 panvk_pool_cleanup(&cmdbuf->desc_pool);
996 panvk_pool_cleanup(&cmdbuf->tls_pool);
997 panvk_pool_cleanup(&cmdbuf->varying_pool);
998 vk_command_buffer_finish(&cmdbuf->vk);
999 vk_free(&device->vk.alloc, cmdbuf);
1000 }
1001
1002 static VkResult
panvk_create_cmdbuf(struct panvk_device * device,struct panvk_cmd_pool * pool,VkCommandBufferLevel level,struct panvk_cmd_buffer ** cmdbuf_out)1003 panvk_create_cmdbuf(struct panvk_device *device,
1004 struct panvk_cmd_pool *pool,
1005 VkCommandBufferLevel level,
1006 struct panvk_cmd_buffer **cmdbuf_out)
1007 {
1008 struct panvk_cmd_buffer *cmdbuf;
1009
1010 cmdbuf = vk_zalloc(&device->vk.alloc, sizeof(*cmdbuf),
1011 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1012 if (!cmdbuf)
1013 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1014
1015 VkResult result = vk_command_buffer_init(&cmdbuf->vk, &device->vk);
1016 if (result != VK_SUCCESS) {
1017 vk_free(&device->vk.alloc, cmdbuf);
1018 return result;
1019 }
1020
1021 cmdbuf->device = device;
1022 cmdbuf->level = level;
1023 cmdbuf->pool = pool;
1024
1025 if (pool) {
1026 list_addtail(&cmdbuf->pool_link, &pool->active_cmd_buffers);
1027 cmdbuf->queue_family_index = pool->queue_family_index;
1028 } else {
1029 /* Init the pool_link so we can safely call list_del when we destroy
1030 * the command buffer
1031 */
1032 list_inithead(&cmdbuf->pool_link);
1033 cmdbuf->queue_family_index = PANVK_QUEUE_GENERAL;
1034 }
1035
1036 panvk_pool_init(&cmdbuf->desc_pool, &device->physical_device->pdev,
1037 pool ? &pool->desc_bo_pool : NULL, 0, 64 * 1024,
1038 "Command buffer descriptor pool", true);
1039 panvk_pool_init(&cmdbuf->tls_pool, &device->physical_device->pdev,
1040 pool ? &pool->tls_bo_pool : NULL,
1041 PAN_BO_INVISIBLE, 64 * 1024, "TLS pool", false);
1042 panvk_pool_init(&cmdbuf->varying_pool, &device->physical_device->pdev,
1043 pool ? &pool->varying_bo_pool : NULL,
1044 PAN_BO_INVISIBLE, 64 * 1024, "Varyings pool", false);
1045 list_inithead(&cmdbuf->batches);
1046 cmdbuf->status = PANVK_CMD_BUFFER_STATUS_INITIAL;
1047 *cmdbuf_out = cmdbuf;
1048 return VK_SUCCESS;
1049 }
1050
1051 VkResult
panvk_per_arch(AllocateCommandBuffers)1052 panvk_per_arch(AllocateCommandBuffers)(VkDevice _device,
1053 const VkCommandBufferAllocateInfo *pAllocateInfo,
1054 VkCommandBuffer *pCommandBuffers)
1055 {
1056 VK_FROM_HANDLE(panvk_device, device, _device);
1057 VK_FROM_HANDLE(panvk_cmd_pool, pool, pAllocateInfo->commandPool);
1058
1059 VkResult result = VK_SUCCESS;
1060 unsigned i;
1061
1062 for (i = 0; i < pAllocateInfo->commandBufferCount; i++) {
1063 struct panvk_cmd_buffer *cmdbuf = NULL;
1064
1065 if (!list_is_empty(&pool->free_cmd_buffers)) {
1066 cmdbuf = list_first_entry(
1067 &pool->free_cmd_buffers, struct panvk_cmd_buffer, pool_link);
1068
1069 list_del(&cmdbuf->pool_link);
1070 list_addtail(&cmdbuf->pool_link, &pool->active_cmd_buffers);
1071
1072 cmdbuf->level = pAllocateInfo->level;
1073 vk_command_buffer_finish(&cmdbuf->vk);
1074 result = vk_command_buffer_init(&cmdbuf->vk, &device->vk);
1075 } else {
1076 result = panvk_create_cmdbuf(device, pool, pAllocateInfo->level, &cmdbuf);
1077 }
1078
1079 if (result != VK_SUCCESS)
1080 goto err_free_cmd_bufs;
1081
1082 pCommandBuffers[i] = panvk_cmd_buffer_to_handle(cmdbuf);
1083 }
1084
1085 return VK_SUCCESS;
1086
1087 err_free_cmd_bufs:
1088 panvk_per_arch(FreeCommandBuffers)(_device, pAllocateInfo->commandPool, i,
1089 pCommandBuffers);
1090 for (unsigned j = 0; j < i; j++)
1091 pCommandBuffers[j] = VK_NULL_HANDLE;
1092
1093 return result;
1094 }
1095
1096 void
panvk_per_arch(FreeCommandBuffers)1097 panvk_per_arch(FreeCommandBuffers)(VkDevice device,
1098 VkCommandPool commandPool,
1099 uint32_t commandBufferCount,
1100 const VkCommandBuffer *pCommandBuffers)
1101 {
1102 for (uint32_t i = 0; i < commandBufferCount; i++) {
1103 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, pCommandBuffers[i]);
1104
1105 if (cmdbuf) {
1106 if (cmdbuf->pool) {
1107 list_del(&cmdbuf->pool_link);
1108 panvk_reset_cmdbuf(cmdbuf);
1109 list_addtail(&cmdbuf->pool_link,
1110 &cmdbuf->pool->free_cmd_buffers);
1111 } else
1112 panvk_destroy_cmdbuf(cmdbuf);
1113 }
1114 }
1115 }
1116
1117 VkResult
panvk_per_arch(ResetCommandBuffer)1118 panvk_per_arch(ResetCommandBuffer)(VkCommandBuffer commandBuffer,
1119 VkCommandBufferResetFlags flags)
1120 {
1121 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
1122
1123 return panvk_reset_cmdbuf(cmdbuf);
1124 }
1125
1126 VkResult
panvk_per_arch(BeginCommandBuffer)1127 panvk_per_arch(BeginCommandBuffer)(VkCommandBuffer commandBuffer,
1128 const VkCommandBufferBeginInfo *pBeginInfo)
1129 {
1130 VK_FROM_HANDLE(panvk_cmd_buffer, cmdbuf, commandBuffer);
1131 VkResult result = VK_SUCCESS;
1132
1133 if (cmdbuf->status != PANVK_CMD_BUFFER_STATUS_INITIAL) {
1134 /* If the command buffer has already been reset with
1135 * vkResetCommandBuffer, no need to do it again.
1136 */
1137 result = panvk_reset_cmdbuf(cmdbuf);
1138 if (result != VK_SUCCESS)
1139 return result;
1140 }
1141
1142 memset(&cmdbuf->state, 0, sizeof(cmdbuf->state));
1143
1144 cmdbuf->status = PANVK_CMD_BUFFER_STATUS_RECORDING;
1145
1146 return VK_SUCCESS;
1147 }
1148
1149 void
panvk_per_arch(DestroyCommandPool)1150 panvk_per_arch(DestroyCommandPool)(VkDevice _device,
1151 VkCommandPool commandPool,
1152 const VkAllocationCallbacks *pAllocator)
1153 {
1154 VK_FROM_HANDLE(panvk_device, device, _device);
1155 VK_FROM_HANDLE(panvk_cmd_pool, pool, commandPool);
1156
1157 list_for_each_entry_safe(struct panvk_cmd_buffer, cmdbuf,
1158 &pool->active_cmd_buffers, pool_link)
1159 panvk_destroy_cmdbuf(cmdbuf);
1160
1161 list_for_each_entry_safe(struct panvk_cmd_buffer, cmdbuf,
1162 &pool->free_cmd_buffers, pool_link)
1163 panvk_destroy_cmdbuf(cmdbuf);
1164
1165 panvk_bo_pool_cleanup(&pool->desc_bo_pool);
1166 panvk_bo_pool_cleanup(&pool->varying_bo_pool);
1167 panvk_bo_pool_cleanup(&pool->tls_bo_pool);
1168 vk_object_free(&device->vk, pAllocator, pool);
1169 }
1170
1171 VkResult
panvk_per_arch(ResetCommandPool)1172 panvk_per_arch(ResetCommandPool)(VkDevice device,
1173 VkCommandPool commandPool,
1174 VkCommandPoolResetFlags flags)
1175 {
1176 VK_FROM_HANDLE(panvk_cmd_pool, pool, commandPool);
1177 VkResult result;
1178
1179 list_for_each_entry(struct panvk_cmd_buffer, cmdbuf, &pool->active_cmd_buffers,
1180 pool_link)
1181 {
1182 result = panvk_reset_cmdbuf(cmdbuf);
1183 if (result != VK_SUCCESS)
1184 return result;
1185 }
1186
1187 return VK_SUCCESS;
1188 }
1189
1190 void
panvk_per_arch(TrimCommandPool)1191 panvk_per_arch(TrimCommandPool)(VkDevice device,
1192 VkCommandPool commandPool,
1193 VkCommandPoolTrimFlags flags)
1194 {
1195 VK_FROM_HANDLE(panvk_cmd_pool, pool, commandPool);
1196
1197 if (!pool)
1198 return;
1199
1200 list_for_each_entry_safe(struct panvk_cmd_buffer, cmdbuf,
1201 &pool->free_cmd_buffers, pool_link)
1202 panvk_destroy_cmdbuf(cmdbuf);
1203 }
1204