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
43static void
44panvk_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
57void
58panvk_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
95static void
96panvk_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
111void
112panvk_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
222void
223panvk_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
236void
237panvk_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
250void
251panvk_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
278void
279panvk_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
297static void
298panvk_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
320static void
321panvk_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
350static void
351panvk_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
372static void
373panvk_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
408static void
409panvk_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
440static void
441panvk_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
493void
494panvk_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
521void
522panvk_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
538static void
539panvk_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
548static void
549panvk_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
595static void
596panvk_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
636static void
637panvk_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
662static void
663panvk_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
676static void
677panvk_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
690void
691panvk_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
768VkResult
769panvk_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
779void
780panvk_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
794void
795panvk_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
805void
806panvk_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
832static void
833panvk_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
864static void
865panvk_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
895void
896panvk_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
909void
910panvk_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
923void
924panvk_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
946static VkResult
947panvk_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
976static void
977panvk_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
1002static VkResult
1003panvk_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
1051VkResult
1052panvk_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
1087err_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
1096void
1097panvk_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
1117VkResult
1118panvk_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
1126VkResult
1127panvk_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
1149void
1150panvk_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
1171VkResult
1172panvk_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
1190void
1191panvk_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