Home | History | Annotate | Line # | Download | only in vulkan
      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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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