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