17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2021 Collabora Ltd.
37ec681f3Smrg *
47ec681f3Smrg * Derived from tu_pipeline.c which is:
57ec681f3Smrg * Copyright © 2016 Red Hat.
67ec681f3Smrg * Copyright © 2016 Bas Nieuwenhuizen
77ec681f3Smrg * Copyright © 2015 Intel Corporation
87ec681f3Smrg *
97ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
107ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
117ec681f3Smrg * to deal in the Software without restriction, including without limitation
127ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
137ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
147ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
157ec681f3Smrg *
167ec681f3Smrg * The above copyright notice and this permission notice (including the next
177ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
187ec681f3Smrg * Software.
197ec681f3Smrg *
207ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
217ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
227ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
237ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
247ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
257ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
267ec681f3Smrg * DEALINGS IN THE SOFTWARE.
277ec681f3Smrg */
287ec681f3Smrg
297ec681f3Smrg#include "panvk_cs.h"
307ec681f3Smrg#include "panvk_private.h"
317ec681f3Smrg
327ec681f3Smrg#include "pan_bo.h"
337ec681f3Smrg
347ec681f3Smrg#include "nir/nir.h"
357ec681f3Smrg#include "nir/nir_builder.h"
367ec681f3Smrg#include "spirv/nir_spirv.h"
377ec681f3Smrg#include "util/debug.h"
387ec681f3Smrg#include "util/mesa-sha1.h"
397ec681f3Smrg#include "util/u_atomic.h"
407ec681f3Smrg#include "vk_format.h"
417ec681f3Smrg#include "vk_util.h"
427ec681f3Smrg
437ec681f3Smrg#include "panfrost/util/pan_lower_framebuffer.h"
447ec681f3Smrg
457ec681f3Smrg#include "panfrost-quirks.h"
467ec681f3Smrg
477ec681f3Smrgstruct panvk_pipeline_builder
487ec681f3Smrg{
497ec681f3Smrg   struct panvk_device *device;
507ec681f3Smrg   struct panvk_pipeline_cache *cache;
517ec681f3Smrg   const VkAllocationCallbacks *alloc;
527ec681f3Smrg   const VkGraphicsPipelineCreateInfo *create_info;
537ec681f3Smrg   const struct panvk_pipeline_layout *layout;
547ec681f3Smrg
557ec681f3Smrg   struct panvk_shader *shaders[MESA_SHADER_STAGES];
567ec681f3Smrg   struct {
577ec681f3Smrg      uint32_t shader_offset;
587ec681f3Smrg      uint32_t rsd_offset;
597ec681f3Smrg      uint32_t sysvals_offset;
607ec681f3Smrg   } stages[MESA_SHADER_STAGES];
617ec681f3Smrg   uint32_t blend_shader_offsets[MAX_RTS];
627ec681f3Smrg   uint32_t shader_total_size;
637ec681f3Smrg   uint32_t static_state_size;
647ec681f3Smrg   uint32_t vpd_offset;
657ec681f3Smrg
667ec681f3Smrg   bool rasterizer_discard;
677ec681f3Smrg   /* these states are affectd by rasterizer_discard */
687ec681f3Smrg   VkSampleCountFlagBits samples;
697ec681f3Smrg   bool use_depth_stencil_attachment;
707ec681f3Smrg   uint8_t active_color_attachments;
717ec681f3Smrg   enum pipe_format color_attachment_formats[MAX_RTS];
727ec681f3Smrg};
737ec681f3Smrg
747ec681f3Smrgstatic VkResult
757ec681f3Smrgpanvk_pipeline_builder_create_pipeline(struct panvk_pipeline_builder *builder,
767ec681f3Smrg                                       struct panvk_pipeline **out_pipeline)
777ec681f3Smrg{
787ec681f3Smrg   struct panvk_device *dev = builder->device;
797ec681f3Smrg
807ec681f3Smrg   struct panvk_pipeline *pipeline =
817ec681f3Smrg      vk_object_zalloc(&dev->vk, builder->alloc,
827ec681f3Smrg                       sizeof(*pipeline), VK_OBJECT_TYPE_PIPELINE);
837ec681f3Smrg   if (!pipeline)
847ec681f3Smrg      return VK_ERROR_OUT_OF_HOST_MEMORY;
857ec681f3Smrg
867ec681f3Smrg   pipeline->layout = builder->layout;
877ec681f3Smrg   *out_pipeline = pipeline;
887ec681f3Smrg   return VK_SUCCESS;
897ec681f3Smrg}
907ec681f3Smrg
917ec681f3Smrgstatic void
927ec681f3Smrgpanvk_pipeline_builder_finish(struct panvk_pipeline_builder *builder)
937ec681f3Smrg{
947ec681f3Smrg   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
957ec681f3Smrg      if (!builder->shaders[i])
967ec681f3Smrg         continue;
977ec681f3Smrg      panvk_shader_destroy(builder->device, builder->shaders[i], builder->alloc);
987ec681f3Smrg   }
997ec681f3Smrg}
1007ec681f3Smrg
1017ec681f3Smrgstatic bool
1027ec681f3Smrgpanvk_pipeline_static_state(struct panvk_pipeline *pipeline, uint32_t id)
1037ec681f3Smrg{
1047ec681f3Smrg   return !(pipeline->dynamic_state_mask & (1 << id));
1057ec681f3Smrg}
1067ec681f3Smrg
1077ec681f3Smrgstatic VkResult
1087ec681f3Smrgpanvk_pipeline_builder_compile_shaders(struct panvk_pipeline_builder *builder,
1097ec681f3Smrg                                       struct panvk_pipeline *pipeline)
1107ec681f3Smrg{
1117ec681f3Smrg   const VkPipelineShaderStageCreateInfo *stage_infos[MESA_SHADER_STAGES] = {
1127ec681f3Smrg      NULL
1137ec681f3Smrg   };
1147ec681f3Smrg   for (uint32_t i = 0; i < builder->create_info->stageCount; i++) {
1157ec681f3Smrg      gl_shader_stage stage = vk_to_mesa_shader_stage(builder->create_info->pStages[i].stage);
1167ec681f3Smrg      stage_infos[stage] = &builder->create_info->pStages[i];
1177ec681f3Smrg   }
1187ec681f3Smrg
1197ec681f3Smrg   /* compile shaders in reverse order */
1207ec681f3Smrg   unsigned sysval_ubo = builder->layout->num_ubos;
1217ec681f3Smrg
1227ec681f3Smrg   for (gl_shader_stage stage = MESA_SHADER_STAGES - 1;
1237ec681f3Smrg        stage > MESA_SHADER_NONE; stage--) {
1247ec681f3Smrg      const VkPipelineShaderStageCreateInfo *stage_info = stage_infos[stage];
1257ec681f3Smrg      if (!stage_info)
1267ec681f3Smrg         continue;
1277ec681f3Smrg
1287ec681f3Smrg      struct panvk_shader *shader;
1297ec681f3Smrg
1307ec681f3Smrg      shader = panvk_per_arch(shader_create)(builder->device, stage, stage_info,
1317ec681f3Smrg                                             builder->layout, sysval_ubo,
1327ec681f3Smrg                                             &pipeline->blend.state,
1337ec681f3Smrg                                             panvk_pipeline_static_state(pipeline,
1347ec681f3Smrg                                                                         VK_DYNAMIC_STATE_BLEND_CONSTANTS),
1357ec681f3Smrg                                             builder->alloc);
1367ec681f3Smrg      if (!shader)
1377ec681f3Smrg         return VK_ERROR_OUT_OF_HOST_MEMORY;
1387ec681f3Smrg
1397ec681f3Smrg      if (shader->info.sysvals.sysval_count)
1407ec681f3Smrg         sysval_ubo++;
1417ec681f3Smrg
1427ec681f3Smrg      builder->shaders[stage] = shader;
1437ec681f3Smrg      builder->shader_total_size = ALIGN_POT(builder->shader_total_size, 128);
1447ec681f3Smrg      builder->stages[stage].shader_offset = builder->shader_total_size;
1457ec681f3Smrg      builder->shader_total_size +=
1467ec681f3Smrg         util_dynarray_num_elements(&shader->binary, uint8_t);
1477ec681f3Smrg   }
1487ec681f3Smrg
1497ec681f3Smrg   return VK_SUCCESS;
1507ec681f3Smrg}
1517ec681f3Smrg
1527ec681f3Smrgstatic VkResult
1537ec681f3Smrgpanvk_pipeline_builder_upload_shaders(struct panvk_pipeline_builder *builder,
1547ec681f3Smrg                                      struct panvk_pipeline *pipeline)
1557ec681f3Smrg{
1567ec681f3Smrg   struct panfrost_bo *bin_bo =
1577ec681f3Smrg      panfrost_bo_create(&builder->device->physical_device->pdev,
1587ec681f3Smrg                         builder->shader_total_size, PAN_BO_EXECUTE,
1597ec681f3Smrg                         "Shader");
1607ec681f3Smrg
1617ec681f3Smrg   pipeline->binary_bo = bin_bo;
1627ec681f3Smrg   panfrost_bo_mmap(bin_bo);
1637ec681f3Smrg
1647ec681f3Smrg   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
1657ec681f3Smrg      const struct panvk_shader *shader = builder->shaders[i];
1667ec681f3Smrg      if (!shader)
1677ec681f3Smrg         continue;
1687ec681f3Smrg
1697ec681f3Smrg      memcpy(pipeline->binary_bo->ptr.cpu + builder->stages[i].shader_offset,
1707ec681f3Smrg             util_dynarray_element(&shader->binary, uint8_t, 0),
1717ec681f3Smrg             util_dynarray_num_elements(&shader->binary, uint8_t));
1727ec681f3Smrg   }
1737ec681f3Smrg
1747ec681f3Smrg   return VK_SUCCESS;
1757ec681f3Smrg}
1767ec681f3Smrg
1777ec681f3Smrgstatic bool
1787ec681f3Smrgpanvk_pipeline_static_sysval(struct panvk_pipeline *pipeline,
1797ec681f3Smrg                             unsigned id)
1807ec681f3Smrg{
1817ec681f3Smrg   switch (id) {
1827ec681f3Smrg   case PAN_SYSVAL_VIEWPORT_SCALE:
1837ec681f3Smrg   case PAN_SYSVAL_VIEWPORT_OFFSET:
1847ec681f3Smrg      return panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT);
1857ec681f3Smrg   default:
1867ec681f3Smrg      return false;
1877ec681f3Smrg   }
1887ec681f3Smrg}
1897ec681f3Smrg
1907ec681f3Smrgstatic void
1917ec681f3Smrgpanvk_pipeline_builder_alloc_static_state_bo(struct panvk_pipeline_builder *builder,
1927ec681f3Smrg                                             struct panvk_pipeline *pipeline)
1937ec681f3Smrg{
1947ec681f3Smrg   struct panfrost_device *pdev =
1957ec681f3Smrg      &builder->device->physical_device->pdev;
1967ec681f3Smrg   unsigned bo_size = 0;
1977ec681f3Smrg
1987ec681f3Smrg   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
1997ec681f3Smrg      const struct panvk_shader *shader = builder->shaders[i];
2007ec681f3Smrg      if (!shader)
2017ec681f3Smrg         continue;
2027ec681f3Smrg
2037ec681f3Smrg      if (pipeline->fs.dynamic_rsd && i == MESA_SHADER_FRAGMENT)
2047ec681f3Smrg         continue;
2057ec681f3Smrg
2067ec681f3Smrg      bo_size = ALIGN_POT(bo_size, pan_alignment(RENDERER_STATE));
2077ec681f3Smrg      builder->stages[i].rsd_offset = bo_size;
2087ec681f3Smrg      bo_size += pan_size(RENDERER_STATE);
2097ec681f3Smrg      if (i == MESA_SHADER_FRAGMENT)
2107ec681f3Smrg         bo_size += pan_size(BLEND) * MAX2(pipeline->blend.state.rt_count, 1);
2117ec681f3Smrg   }
2127ec681f3Smrg
2137ec681f3Smrg   if (panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT) &&
2147ec681f3Smrg       panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_SCISSOR)) {
2157ec681f3Smrg      bo_size = ALIGN_POT(bo_size, pan_alignment(VIEWPORT));
2167ec681f3Smrg      builder->vpd_offset = bo_size;
2177ec681f3Smrg      bo_size += pan_size(VIEWPORT);
2187ec681f3Smrg   }
2197ec681f3Smrg
2207ec681f3Smrg   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
2217ec681f3Smrg      const struct panvk_shader *shader = builder->shaders[i];
2227ec681f3Smrg      if (!shader || !shader->info.sysvals.sysval_count)
2237ec681f3Smrg         continue;
2247ec681f3Smrg
2257ec681f3Smrg      bool static_sysvals = true;
2267ec681f3Smrg      for (unsigned s = 0; s < shader->info.sysvals.sysval_count; s++) {
2277ec681f3Smrg         unsigned id = shader->info.sysvals.sysvals[i];
2287ec681f3Smrg         static_sysvals &= panvk_pipeline_static_sysval(pipeline, id);
2297ec681f3Smrg         switch (PAN_SYSVAL_TYPE(id)) {
2307ec681f3Smrg         case PAN_SYSVAL_VIEWPORT_SCALE:
2317ec681f3Smrg         case PAN_SYSVAL_VIEWPORT_OFFSET:
2327ec681f3Smrg            pipeline->sysvals[i].dirty_mask |= PANVK_DYNAMIC_VIEWPORT;
2337ec681f3Smrg            break;
2347ec681f3Smrg         default:
2357ec681f3Smrg            break;
2367ec681f3Smrg         }
2377ec681f3Smrg      }
2387ec681f3Smrg
2397ec681f3Smrg      if (!static_sysvals) {
2407ec681f3Smrg         builder->stages[i].sysvals_offset = ~0;
2417ec681f3Smrg         continue;
2427ec681f3Smrg      }
2437ec681f3Smrg
2447ec681f3Smrg      bo_size = ALIGN_POT(bo_size, 16);
2457ec681f3Smrg      builder->stages[i].sysvals_offset = bo_size;
2467ec681f3Smrg      bo_size += shader->info.sysvals.sysval_count * 16;
2477ec681f3Smrg   }
2487ec681f3Smrg
2497ec681f3Smrg   if (bo_size) {
2507ec681f3Smrg      pipeline->state_bo =
2517ec681f3Smrg         panfrost_bo_create(pdev, bo_size, 0, "Pipeline descriptors");
2527ec681f3Smrg      panfrost_bo_mmap(pipeline->state_bo);
2537ec681f3Smrg   }
2547ec681f3Smrg}
2557ec681f3Smrg
2567ec681f3Smrgstatic void
2577ec681f3Smrgpanvk_pipeline_builder_upload_sysval(struct panvk_pipeline_builder *builder,
2587ec681f3Smrg                                     struct panvk_pipeline *pipeline,
2597ec681f3Smrg                                     unsigned id, union panvk_sysval_data *data)
2607ec681f3Smrg{
2617ec681f3Smrg   switch (PAN_SYSVAL_TYPE(id)) {
2627ec681f3Smrg   case PAN_SYSVAL_VIEWPORT_SCALE:
2637ec681f3Smrg      panvk_sysval_upload_viewport_scale(builder->create_info->pViewportState->pViewports,
2647ec681f3Smrg                                         data);
2657ec681f3Smrg      break;
2667ec681f3Smrg   case PAN_SYSVAL_VIEWPORT_OFFSET:
2677ec681f3Smrg      panvk_sysval_upload_viewport_offset(builder->create_info->pViewportState->pViewports,
2687ec681f3Smrg                                          data);
2697ec681f3Smrg      break;
2707ec681f3Smrg   default:
2717ec681f3Smrg      unreachable("Invalid static sysval");
2727ec681f3Smrg   }
2737ec681f3Smrg}
2747ec681f3Smrg
2757ec681f3Smrgstatic void
2767ec681f3Smrgpanvk_pipeline_builder_init_sysvals(struct panvk_pipeline_builder *builder,
2777ec681f3Smrg                                    struct panvk_pipeline *pipeline,
2787ec681f3Smrg                                    gl_shader_stage stage)
2797ec681f3Smrg{
2807ec681f3Smrg   const struct panvk_shader *shader = builder->shaders[stage];
2817ec681f3Smrg
2827ec681f3Smrg   pipeline->sysvals[stage].ids = shader->info.sysvals;
2837ec681f3Smrg   pipeline->sysvals[stage].ubo_idx = shader->sysval_ubo;
2847ec681f3Smrg
2857ec681f3Smrg   if (!shader->info.sysvals.sysval_count ||
2867ec681f3Smrg       builder->stages[stage].sysvals_offset == ~0)
2877ec681f3Smrg      return;
2887ec681f3Smrg
2897ec681f3Smrg   union panvk_sysval_data *static_data =
2907ec681f3Smrg      pipeline->state_bo->ptr.cpu + builder->stages[stage].sysvals_offset;
2917ec681f3Smrg
2927ec681f3Smrg   pipeline->sysvals[stage].ubo =
2937ec681f3Smrg      pipeline->state_bo->ptr.gpu + builder->stages[stage].sysvals_offset;
2947ec681f3Smrg
2957ec681f3Smrg   for (unsigned i = 0; i < shader->info.sysvals.sysval_count; i++) {
2967ec681f3Smrg      unsigned id = shader->info.sysvals.sysvals[i];
2977ec681f3Smrg
2987ec681f3Smrg      panvk_pipeline_builder_upload_sysval(builder,
2997ec681f3Smrg                                           pipeline,
3007ec681f3Smrg                                           id, &static_data[i]);
3017ec681f3Smrg   }
3027ec681f3Smrg}
3037ec681f3Smrg
3047ec681f3Smrgstatic void
3057ec681f3Smrgpanvk_pipeline_builder_init_shaders(struct panvk_pipeline_builder *builder,
3067ec681f3Smrg                                    struct panvk_pipeline *pipeline)
3077ec681f3Smrg{
3087ec681f3Smrg   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
3097ec681f3Smrg      const struct panvk_shader *shader = builder->shaders[i];
3107ec681f3Smrg      if (!shader)
3117ec681f3Smrg         continue;
3127ec681f3Smrg
3137ec681f3Smrg      pipeline->tls_size = MAX2(pipeline->tls_size, shader->info.tls_size);
3147ec681f3Smrg      pipeline->wls_size = MAX2(pipeline->wls_size, shader->info.wls_size);
3157ec681f3Smrg
3167ec681f3Smrg      if (i == MESA_SHADER_VERTEX && shader->info.vs.writes_point_size)
3177ec681f3Smrg         pipeline->ia.writes_point_size = true;
3187ec681f3Smrg
3197ec681f3Smrg      mali_ptr shader_ptr = pipeline->binary_bo->ptr.gpu +
3207ec681f3Smrg                            builder->stages[i].shader_offset;
3217ec681f3Smrg
3227ec681f3Smrg      void *rsd = pipeline->state_bo->ptr.cpu + builder->stages[i].rsd_offset;
3237ec681f3Smrg      mali_ptr gpu_rsd = pipeline->state_bo->ptr.gpu + builder->stages[i].rsd_offset;
3247ec681f3Smrg
3257ec681f3Smrg      if (i != MESA_SHADER_FRAGMENT) {
3267ec681f3Smrg         panvk_per_arch(emit_non_fs_rsd)(builder->device, &shader->info, shader_ptr, rsd);
3277ec681f3Smrg      } else if (!pipeline->fs.dynamic_rsd) {
3287ec681f3Smrg         void *bd = rsd + pan_size(RENDERER_STATE);
3297ec681f3Smrg
3307ec681f3Smrg         panvk_per_arch(emit_base_fs_rsd)(builder->device, pipeline, rsd);
3317ec681f3Smrg         for (unsigned rt = 0; rt < MAX2(pipeline->blend.state.rt_count, 1); rt++) {
3327ec681f3Smrg            panvk_per_arch(emit_blend)(builder->device, pipeline, rt, bd);
3337ec681f3Smrg            bd += pan_size(BLEND);
3347ec681f3Smrg         }
3357ec681f3Smrg      } else {
3367ec681f3Smrg         gpu_rsd = 0;
3377ec681f3Smrg         panvk_per_arch(emit_base_fs_rsd)(builder->device, pipeline, &pipeline->fs.rsd_template);
3387ec681f3Smrg         for (unsigned rt = 0; rt < MAX2(pipeline->blend.state.rt_count, 1); rt++) {
3397ec681f3Smrg            panvk_per_arch(emit_blend)(builder->device, pipeline, rt,
3407ec681f3Smrg                                       &pipeline->blend.bd_template[rt]);
3417ec681f3Smrg         }
3427ec681f3Smrg      }
3437ec681f3Smrg
3447ec681f3Smrg      pipeline->rsds[i] = gpu_rsd;
3457ec681f3Smrg      panvk_pipeline_builder_init_sysvals(builder, pipeline, i);
3467ec681f3Smrg   }
3477ec681f3Smrg
3487ec681f3Smrg   pipeline->num_ubos = builder->layout->num_ubos;
3497ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(pipeline->sysvals); i++) {
3507ec681f3Smrg      if (pipeline->sysvals[i].ids.sysval_count)
3517ec681f3Smrg         pipeline->num_ubos = MAX2(pipeline->num_ubos, pipeline->sysvals[i].ubo_idx + 1);
3527ec681f3Smrg   }
3537ec681f3Smrg
3547ec681f3Smrg   pipeline->num_sysvals = 0;
3557ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(pipeline->sysvals); i++)
3567ec681f3Smrg      pipeline->num_sysvals += pipeline->sysvals[i].ids.sysval_count;
3577ec681f3Smrg}
3587ec681f3Smrg
3597ec681f3Smrg
3607ec681f3Smrgstatic void
3617ec681f3Smrgpanvk_pipeline_builder_parse_viewport(struct panvk_pipeline_builder *builder,
3627ec681f3Smrg                                      struct panvk_pipeline *pipeline)
3637ec681f3Smrg{
3647ec681f3Smrg   /* The spec says:
3657ec681f3Smrg    *
3667ec681f3Smrg    *    pViewportState is a pointer to an instance of the
3677ec681f3Smrg    *    VkPipelineViewportStateCreateInfo structure, and is ignored if the
3687ec681f3Smrg    *    pipeline has rasterization disabled.
3697ec681f3Smrg    */
3707ec681f3Smrg   if (!builder->rasterizer_discard &&
3717ec681f3Smrg       panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT) &&
3727ec681f3Smrg       panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_SCISSOR)) {
3737ec681f3Smrg      void *vpd = pipeline->state_bo->ptr.cpu + builder->vpd_offset;
3747ec681f3Smrg      panvk_per_arch(emit_viewport)(builder->create_info->pViewportState->pViewports,
3757ec681f3Smrg                                    builder->create_info->pViewportState->pScissors,
3767ec681f3Smrg                                    vpd);
3777ec681f3Smrg      pipeline->vpd = pipeline->state_bo->ptr.gpu +
3787ec681f3Smrg                      builder->vpd_offset;
3797ec681f3Smrg   }
3807ec681f3Smrg   if (panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT))
3817ec681f3Smrg      pipeline->viewport = builder->create_info->pViewportState->pViewports[0];
3827ec681f3Smrg
3837ec681f3Smrg   if (panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_SCISSOR))
3847ec681f3Smrg      pipeline->scissor = builder->create_info->pViewportState->pScissors[0];
3857ec681f3Smrg}
3867ec681f3Smrg
3877ec681f3Smrgstatic void
3887ec681f3Smrgpanvk_pipeline_builder_parse_dynamic(struct panvk_pipeline_builder *builder,
3897ec681f3Smrg                                     struct panvk_pipeline *pipeline)
3907ec681f3Smrg{
3917ec681f3Smrg   const VkPipelineDynamicStateCreateInfo *dynamic_info =
3927ec681f3Smrg      builder->create_info->pDynamicState;
3937ec681f3Smrg
3947ec681f3Smrg   if (!dynamic_info)
3957ec681f3Smrg      return;
3967ec681f3Smrg
3977ec681f3Smrg   for (uint32_t i = 0; i < dynamic_info->dynamicStateCount; i++) {
3987ec681f3Smrg      VkDynamicState state = dynamic_info->pDynamicStates[i];
3997ec681f3Smrg      switch (state) {
4007ec681f3Smrg      case VK_DYNAMIC_STATE_VIEWPORT ... VK_DYNAMIC_STATE_STENCIL_REFERENCE:
4017ec681f3Smrg         pipeline->dynamic_state_mask |= 1 << state;
4027ec681f3Smrg         break;
4037ec681f3Smrg      default:
4047ec681f3Smrg         unreachable("unsupported dynamic state");
4057ec681f3Smrg      }
4067ec681f3Smrg   }
4077ec681f3Smrg
4087ec681f3Smrg}
4097ec681f3Smrg
4107ec681f3Smrgstatic enum mali_draw_mode
4117ec681f3Smrgtranslate_prim_topology(VkPrimitiveTopology in)
4127ec681f3Smrg{
4137ec681f3Smrg   switch (in) {
4147ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
4157ec681f3Smrg      return MALI_DRAW_MODE_POINTS;
4167ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
4177ec681f3Smrg      return MALI_DRAW_MODE_LINES;
4187ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
4197ec681f3Smrg      return MALI_DRAW_MODE_LINE_STRIP;
4207ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
4217ec681f3Smrg      return MALI_DRAW_MODE_TRIANGLES;
4227ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
4237ec681f3Smrg      return MALI_DRAW_MODE_TRIANGLE_STRIP;
4247ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
4257ec681f3Smrg      return MALI_DRAW_MODE_TRIANGLE_FAN;
4267ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
4277ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
4287ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
4297ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
4307ec681f3Smrg   case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
4317ec681f3Smrg   default:
4327ec681f3Smrg      unreachable("Invalid primitive type");
4337ec681f3Smrg   }
4347ec681f3Smrg}
4357ec681f3Smrg
4367ec681f3Smrgstatic void
4377ec681f3Smrgpanvk_pipeline_builder_parse_input_assembly(struct panvk_pipeline_builder *builder,
4387ec681f3Smrg                                            struct panvk_pipeline *pipeline)
4397ec681f3Smrg{
4407ec681f3Smrg   pipeline->ia.primitive_restart =
4417ec681f3Smrg      builder->create_info->pInputAssemblyState->primitiveRestartEnable;
4427ec681f3Smrg   pipeline->ia.topology =
4437ec681f3Smrg      translate_prim_topology(builder->create_info->pInputAssemblyState->topology);
4447ec681f3Smrg}
4457ec681f3Smrg
4467ec681f3Smrgstatic enum pipe_logicop
4477ec681f3Smrgtranslate_logicop(VkLogicOp in)
4487ec681f3Smrg{
4497ec681f3Smrg   switch (in) {
4507ec681f3Smrg   case VK_LOGIC_OP_CLEAR: return PIPE_LOGICOP_CLEAR;
4517ec681f3Smrg   case VK_LOGIC_OP_AND: return PIPE_LOGICOP_AND;
4527ec681f3Smrg   case VK_LOGIC_OP_AND_REVERSE: return PIPE_LOGICOP_AND_REVERSE;
4537ec681f3Smrg   case VK_LOGIC_OP_COPY: return PIPE_LOGICOP_COPY;
4547ec681f3Smrg   case VK_LOGIC_OP_AND_INVERTED: return PIPE_LOGICOP_AND_INVERTED;
4557ec681f3Smrg   case VK_LOGIC_OP_NO_OP: return PIPE_LOGICOP_NOOP;
4567ec681f3Smrg   case VK_LOGIC_OP_XOR: return PIPE_LOGICOP_XOR;
4577ec681f3Smrg   case VK_LOGIC_OP_OR: return PIPE_LOGICOP_OR;
4587ec681f3Smrg   case VK_LOGIC_OP_NOR: return PIPE_LOGICOP_NOR;
4597ec681f3Smrg   case VK_LOGIC_OP_EQUIVALENT: return PIPE_LOGICOP_EQUIV;
4607ec681f3Smrg   case VK_LOGIC_OP_INVERT: return PIPE_LOGICOP_INVERT;
4617ec681f3Smrg   case VK_LOGIC_OP_OR_REVERSE: return PIPE_LOGICOP_OR_REVERSE;
4627ec681f3Smrg   case VK_LOGIC_OP_COPY_INVERTED: return PIPE_LOGICOP_COPY_INVERTED;
4637ec681f3Smrg   case VK_LOGIC_OP_OR_INVERTED: return PIPE_LOGICOP_OR_INVERTED;
4647ec681f3Smrg   case VK_LOGIC_OP_NAND: return PIPE_LOGICOP_NAND;
4657ec681f3Smrg   case VK_LOGIC_OP_SET: return PIPE_LOGICOP_SET;
4667ec681f3Smrg   default: unreachable("Invalid logicop");
4677ec681f3Smrg   }
4687ec681f3Smrg}
4697ec681f3Smrg
4707ec681f3Smrgstatic enum blend_func
4717ec681f3Smrgtranslate_blend_op(VkBlendOp in)
4727ec681f3Smrg{
4737ec681f3Smrg   switch (in) {
4747ec681f3Smrg   case VK_BLEND_OP_ADD: return BLEND_FUNC_ADD;
4757ec681f3Smrg   case VK_BLEND_OP_SUBTRACT: return BLEND_FUNC_SUBTRACT;
4767ec681f3Smrg   case VK_BLEND_OP_REVERSE_SUBTRACT: return BLEND_FUNC_REVERSE_SUBTRACT;
4777ec681f3Smrg   case VK_BLEND_OP_MIN: return BLEND_FUNC_MIN;
4787ec681f3Smrg   case VK_BLEND_OP_MAX: return BLEND_FUNC_MAX;
4797ec681f3Smrg   default: unreachable("Invalid blend op");
4807ec681f3Smrg   }
4817ec681f3Smrg}
4827ec681f3Smrg
4837ec681f3Smrgstatic enum blend_factor
4847ec681f3Smrgtranslate_blend_factor(VkBlendFactor in, bool dest_has_alpha)
4857ec681f3Smrg{
4867ec681f3Smrg   switch (in) {
4877ec681f3Smrg   case VK_BLEND_FACTOR_ZERO:
4887ec681f3Smrg   case VK_BLEND_FACTOR_ONE:
4897ec681f3Smrg      return BLEND_FACTOR_ZERO;
4907ec681f3Smrg   case VK_BLEND_FACTOR_SRC_COLOR:
4917ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
4927ec681f3Smrg      return BLEND_FACTOR_SRC_COLOR;
4937ec681f3Smrg   case VK_BLEND_FACTOR_DST_COLOR:
4947ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
4957ec681f3Smrg      return BLEND_FACTOR_DST_COLOR;
4967ec681f3Smrg   case VK_BLEND_FACTOR_SRC_ALPHA:
4977ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
4987ec681f3Smrg      return BLEND_FACTOR_SRC_ALPHA;
4997ec681f3Smrg   case VK_BLEND_FACTOR_DST_ALPHA:
5007ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
5017ec681f3Smrg      return dest_has_alpha ? BLEND_FACTOR_DST_ALPHA : BLEND_FACTOR_ZERO;
5027ec681f3Smrg   case VK_BLEND_FACTOR_CONSTANT_COLOR:
5037ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
5047ec681f3Smrg      return BLEND_FACTOR_CONSTANT_COLOR;
5057ec681f3Smrg   case VK_BLEND_FACTOR_CONSTANT_ALPHA:
5067ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
5077ec681f3Smrg      return BLEND_FACTOR_CONSTANT_ALPHA;
5087ec681f3Smrg   case VK_BLEND_FACTOR_SRC1_COLOR:
5097ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
5107ec681f3Smrg      return BLEND_FACTOR_SRC1_COLOR;
5117ec681f3Smrg   case VK_BLEND_FACTOR_SRC1_ALPHA:
5127ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
5137ec681f3Smrg      return BLEND_FACTOR_SRC1_ALPHA;
5147ec681f3Smrg   case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE:
5157ec681f3Smrg      return BLEND_FACTOR_SRC_ALPHA_SATURATE;
5167ec681f3Smrg   default: unreachable("Invalid blend factor");
5177ec681f3Smrg   }
5187ec681f3Smrg}
5197ec681f3Smrg
5207ec681f3Smrgstatic bool
5217ec681f3Smrginverted_blend_factor(VkBlendFactor in, bool dest_has_alpha)
5227ec681f3Smrg{
5237ec681f3Smrg   switch (in) {
5247ec681f3Smrg   case VK_BLEND_FACTOR_ONE:
5257ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
5267ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
5277ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
5287ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
5297ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
5307ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
5317ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
5327ec681f3Smrg      return true;
5337ec681f3Smrg   case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
5347ec681f3Smrg      return dest_has_alpha ? true : false;
5357ec681f3Smrg   case VK_BLEND_FACTOR_DST_ALPHA:
5367ec681f3Smrg      return !dest_has_alpha ? true : false;
5377ec681f3Smrg   default:
5387ec681f3Smrg      return false;
5397ec681f3Smrg   }
5407ec681f3Smrg}
5417ec681f3Smrg
5427ec681f3Smrgbool
5437ec681f3Smrgpanvk_per_arch(blend_needs_lowering)(const struct panfrost_device *dev,
5447ec681f3Smrg                                     const struct pan_blend_state *state,
5457ec681f3Smrg                                     unsigned rt)
5467ec681f3Smrg{
5477ec681f3Smrg   /* LogicOp requires a blend shader */
5487ec681f3Smrg   if (state->logicop_enable)
5497ec681f3Smrg      return true;
5507ec681f3Smrg
5517ec681f3Smrg   /* Not all formats can be blended by fixed-function hardware */
5527ec681f3Smrg   if (!panfrost_blendable_formats_v7[state->rts[rt].format].internal)
5537ec681f3Smrg      return true;
5547ec681f3Smrg
5557ec681f3Smrg   unsigned constant_mask = pan_blend_constant_mask(state->rts[rt].equation);
5567ec681f3Smrg
5577ec681f3Smrg   /* v6 doesn't support blend constants in FF blend equations.
5587ec681f3Smrg    * v7 only uses the constant from RT 0 (TODO: what if it's the same
5597ec681f3Smrg    * constant? or a constant is shared?)
5607ec681f3Smrg    */
5617ec681f3Smrg   if (constant_mask && (PAN_ARCH == 6 || (PAN_ARCH == 7 && rt > 0)))
5627ec681f3Smrg      return true;
5637ec681f3Smrg
5647ec681f3Smrg   if (!pan_blend_is_homogenous_constant(constant_mask, state->constants))
5657ec681f3Smrg      return true;
5667ec681f3Smrg
5677ec681f3Smrg   bool supports_2src = pan_blend_supports_2src(dev->arch);
5687ec681f3Smrg   return !pan_blend_can_fixed_function(state->rts[rt].equation, supports_2src);
5697ec681f3Smrg}
5707ec681f3Smrg
5717ec681f3Smrgstatic void
5727ec681f3Smrgpanvk_pipeline_builder_parse_color_blend(struct panvk_pipeline_builder *builder,
5737ec681f3Smrg                                         struct panvk_pipeline *pipeline)
5747ec681f3Smrg{
5757ec681f3Smrg   struct panfrost_device *pdev = &builder->device->physical_device->pdev;
5767ec681f3Smrg   pipeline->blend.state.logicop_enable =
5777ec681f3Smrg      builder->create_info->pColorBlendState->logicOpEnable;
5787ec681f3Smrg   pipeline->blend.state.logicop_func =
5797ec681f3Smrg      translate_logicop(builder->create_info->pColorBlendState->logicOp);
5807ec681f3Smrg   pipeline->blend.state.rt_count = util_last_bit(builder->active_color_attachments);
5817ec681f3Smrg   memcpy(pipeline->blend.state.constants,
5827ec681f3Smrg          builder->create_info->pColorBlendState->blendConstants,
5837ec681f3Smrg          sizeof(pipeline->blend.state.constants));
5847ec681f3Smrg
5857ec681f3Smrg   for (unsigned i = 0; i < pipeline->blend.state.rt_count; i++) {
5867ec681f3Smrg      const VkPipelineColorBlendAttachmentState *in =
5877ec681f3Smrg         &builder->create_info->pColorBlendState->pAttachments[i];
5887ec681f3Smrg      struct pan_blend_rt_state *out = &pipeline->blend.state.rts[i];
5897ec681f3Smrg
5907ec681f3Smrg      out->format = builder->color_attachment_formats[i];
5917ec681f3Smrg
5927ec681f3Smrg      bool dest_has_alpha = util_format_has_alpha(out->format);
5937ec681f3Smrg
5947ec681f3Smrg      out->nr_samples = builder->create_info->pMultisampleState->rasterizationSamples;
5957ec681f3Smrg      out->equation.blend_enable = in->blendEnable;
5967ec681f3Smrg      out->equation.color_mask = in->colorWriteMask;
5977ec681f3Smrg      out->equation.rgb_func = translate_blend_op(in->colorBlendOp);
5987ec681f3Smrg      out->equation.rgb_src_factor = translate_blend_factor(in->srcColorBlendFactor, dest_has_alpha);
5997ec681f3Smrg      out->equation.rgb_invert_src_factor = inverted_blend_factor(in->srcColorBlendFactor, dest_has_alpha);
6007ec681f3Smrg      out->equation.rgb_dst_factor = translate_blend_factor(in->dstColorBlendFactor, dest_has_alpha);
6017ec681f3Smrg      out->equation.rgb_invert_dst_factor = inverted_blend_factor(in->dstColorBlendFactor, dest_has_alpha);
6027ec681f3Smrg      out->equation.alpha_func = translate_blend_op(in->alphaBlendOp);
6037ec681f3Smrg      out->equation.alpha_src_factor = translate_blend_factor(in->srcAlphaBlendFactor, dest_has_alpha);
6047ec681f3Smrg      out->equation.alpha_invert_src_factor = inverted_blend_factor(in->srcAlphaBlendFactor, dest_has_alpha);
6057ec681f3Smrg      out->equation.alpha_dst_factor = translate_blend_factor(in->dstAlphaBlendFactor, dest_has_alpha);
6067ec681f3Smrg      out->equation.alpha_invert_dst_factor = inverted_blend_factor(in->dstAlphaBlendFactor, dest_has_alpha);
6077ec681f3Smrg
6087ec681f3Smrg      pipeline->blend.reads_dest |= pan_blend_reads_dest(out->equation);
6097ec681f3Smrg
6107ec681f3Smrg      unsigned constant_mask =
6117ec681f3Smrg         panvk_per_arch(blend_needs_lowering)(pdev, &pipeline->blend.state, i) ?
6127ec681f3Smrg         0 : pan_blend_constant_mask(out->equation);
6137ec681f3Smrg      pipeline->blend.constant[i].index = ffs(constant_mask) - 1;
6147ec681f3Smrg      if (constant_mask && PAN_ARCH >= 6) {
6157ec681f3Smrg         /* On Bifrost, the blend constant is expressed with a UNORM of the
6167ec681f3Smrg          * size of the target format. The value is then shifted such that
6177ec681f3Smrg          * used bits are in the MSB. Here we calculate the factor at pipeline
6187ec681f3Smrg          * creation time so we only have to do a
6197ec681f3Smrg          *   hw_constant = float_constant * factor;
6207ec681f3Smrg          * at descriptor emission time.
6217ec681f3Smrg          */
6227ec681f3Smrg         const struct util_format_description *format_desc =
6237ec681f3Smrg            util_format_description(out->format);
6247ec681f3Smrg         unsigned chan_size = 0;
6257ec681f3Smrg         for (unsigned c = 0; c < format_desc->nr_channels; c++)
6267ec681f3Smrg            chan_size = MAX2(format_desc->channel[c].size, chan_size);
6277ec681f3Smrg         pipeline->blend.constant[i].bifrost_factor =
6287ec681f3Smrg            ((1 << chan_size) - 1) << (16 - chan_size);
6297ec681f3Smrg      }
6307ec681f3Smrg   }
6317ec681f3Smrg}
6327ec681f3Smrg
6337ec681f3Smrgstatic void
6347ec681f3Smrgpanvk_pipeline_builder_parse_multisample(struct panvk_pipeline_builder *builder,
6357ec681f3Smrg                                         struct panvk_pipeline *pipeline)
6367ec681f3Smrg{
6377ec681f3Smrg   unsigned nr_samples =
6387ec681f3Smrg      MAX2(builder->create_info->pMultisampleState->rasterizationSamples, 1);
6397ec681f3Smrg
6407ec681f3Smrg   pipeline->ms.rast_samples =
6417ec681f3Smrg      builder->create_info->pMultisampleState->rasterizationSamples;
6427ec681f3Smrg   pipeline->ms.sample_mask =
6437ec681f3Smrg      builder->create_info->pMultisampleState->pSampleMask ?
6447ec681f3Smrg      builder->create_info->pMultisampleState->pSampleMask[0] : UINT16_MAX;
6457ec681f3Smrg   pipeline->ms.min_samples =
6467ec681f3Smrg      MAX2(builder->create_info->pMultisampleState->minSampleShading * nr_samples, 1);
6477ec681f3Smrg}
6487ec681f3Smrg
6497ec681f3Smrgstatic enum mali_stencil_op
6507ec681f3Smrgtranslate_stencil_op(VkStencilOp in)
6517ec681f3Smrg{
6527ec681f3Smrg   switch (in) {
6537ec681f3Smrg   case VK_STENCIL_OP_KEEP: return MALI_STENCIL_OP_KEEP;
6547ec681f3Smrg   case VK_STENCIL_OP_ZERO: return MALI_STENCIL_OP_ZERO;
6557ec681f3Smrg   case VK_STENCIL_OP_REPLACE: return MALI_STENCIL_OP_REPLACE;
6567ec681f3Smrg   case VK_STENCIL_OP_INCREMENT_AND_CLAMP: return MALI_STENCIL_OP_INCR_SAT;
6577ec681f3Smrg   case VK_STENCIL_OP_DECREMENT_AND_CLAMP: return MALI_STENCIL_OP_DECR_SAT;
6587ec681f3Smrg   case VK_STENCIL_OP_INCREMENT_AND_WRAP: return MALI_STENCIL_OP_INCR_WRAP;
6597ec681f3Smrg   case VK_STENCIL_OP_DECREMENT_AND_WRAP: return MALI_STENCIL_OP_DECR_WRAP;
6607ec681f3Smrg   case VK_STENCIL_OP_INVERT: return MALI_STENCIL_OP_INVERT;
6617ec681f3Smrg   default: unreachable("Invalid stencil op");
6627ec681f3Smrg   }
6637ec681f3Smrg}
6647ec681f3Smrg
6657ec681f3Smrgstatic void
6667ec681f3Smrgpanvk_pipeline_builder_parse_zs(struct panvk_pipeline_builder *builder,
6677ec681f3Smrg                                struct panvk_pipeline *pipeline)
6687ec681f3Smrg{
6697ec681f3Smrg   pipeline->zs.z_test = builder->create_info->pDepthStencilState->depthTestEnable;
6707ec681f3Smrg   pipeline->zs.z_write = builder->create_info->pDepthStencilState->depthWriteEnable;
6717ec681f3Smrg   pipeline->zs.z_compare_func =
6727ec681f3Smrg      panvk_per_arch(translate_compare_func)(builder->create_info->pDepthStencilState->depthCompareOp);
6737ec681f3Smrg   pipeline->zs.s_test = builder->create_info->pDepthStencilState->stencilTestEnable;
6747ec681f3Smrg   pipeline->zs.s_front.fail_op =
6757ec681f3Smrg      translate_stencil_op(builder->create_info->pDepthStencilState->front.failOp);
6767ec681f3Smrg   pipeline->zs.s_front.pass_op =
6777ec681f3Smrg      translate_stencil_op(builder->create_info->pDepthStencilState->front.passOp);
6787ec681f3Smrg   pipeline->zs.s_front.z_fail_op =
6797ec681f3Smrg      translate_stencil_op(builder->create_info->pDepthStencilState->front.depthFailOp);
6807ec681f3Smrg   pipeline->zs.s_front.compare_func =
6817ec681f3Smrg      panvk_per_arch(translate_compare_func)(builder->create_info->pDepthStencilState->front.compareOp);
6827ec681f3Smrg   pipeline->zs.s_front.compare_mask =
6837ec681f3Smrg      builder->create_info->pDepthStencilState->front.compareMask;
6847ec681f3Smrg   pipeline->zs.s_front.write_mask =
6857ec681f3Smrg      builder->create_info->pDepthStencilState->front.writeMask;
6867ec681f3Smrg   pipeline->zs.s_front.ref =
6877ec681f3Smrg      builder->create_info->pDepthStencilState->front.reference;
6887ec681f3Smrg   pipeline->zs.s_back.fail_op =
6897ec681f3Smrg      translate_stencil_op(builder->create_info->pDepthStencilState->back.failOp);
6907ec681f3Smrg   pipeline->zs.s_back.pass_op =
6917ec681f3Smrg      translate_stencil_op(builder->create_info->pDepthStencilState->back.passOp);
6927ec681f3Smrg   pipeline->zs.s_back.z_fail_op =
6937ec681f3Smrg      translate_stencil_op(builder->create_info->pDepthStencilState->back.depthFailOp);
6947ec681f3Smrg   pipeline->zs.s_back.compare_func =
6957ec681f3Smrg      panvk_per_arch(translate_compare_func)(builder->create_info->pDepthStencilState->back.compareOp);
6967ec681f3Smrg   pipeline->zs.s_back.compare_mask =
6977ec681f3Smrg      builder->create_info->pDepthStencilState->back.compareMask;
6987ec681f3Smrg   pipeline->zs.s_back.write_mask =
6997ec681f3Smrg      builder->create_info->pDepthStencilState->back.writeMask;
7007ec681f3Smrg   pipeline->zs.s_back.ref =
7017ec681f3Smrg      builder->create_info->pDepthStencilState->back.reference;
7027ec681f3Smrg}
7037ec681f3Smrg
7047ec681f3Smrgstatic void
7057ec681f3Smrgpanvk_pipeline_builder_parse_rast(struct panvk_pipeline_builder *builder,
7067ec681f3Smrg                                  struct panvk_pipeline *pipeline)
7077ec681f3Smrg{
7087ec681f3Smrg   pipeline->rast.clamp_depth = builder->create_info->pRasterizationState->depthClampEnable;
7097ec681f3Smrg   pipeline->rast.depth_bias.enable = builder->create_info->pRasterizationState->depthBiasEnable;
7107ec681f3Smrg   pipeline->rast.depth_bias.constant_factor =
7117ec681f3Smrg      builder->create_info->pRasterizationState->depthBiasConstantFactor;
7127ec681f3Smrg   pipeline->rast.depth_bias.clamp = builder->create_info->pRasterizationState->depthBiasClamp;
7137ec681f3Smrg   pipeline->rast.depth_bias.slope_factor = builder->create_info->pRasterizationState->depthBiasSlopeFactor;
7147ec681f3Smrg   pipeline->rast.front_ccw = builder->create_info->pRasterizationState->frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE;
7157ec681f3Smrg   pipeline->rast.cull_front_face = builder->create_info->pRasterizationState->cullMode & VK_CULL_MODE_FRONT_BIT;
7167ec681f3Smrg   pipeline->rast.cull_back_face = builder->create_info->pRasterizationState->cullMode & VK_CULL_MODE_BACK_BIT;
7177ec681f3Smrg}
7187ec681f3Smrg
7197ec681f3Smrgstatic bool
7207ec681f3Smrgpanvk_fs_required(struct panvk_pipeline *pipeline)
7217ec681f3Smrg{
7227ec681f3Smrg   const struct pan_shader_info *info = &pipeline->fs.info;
7237ec681f3Smrg
7247ec681f3Smrg   /* If we generally have side effects */
7257ec681f3Smrg   if (info->fs.sidefx)
7267ec681f3Smrg      return true;
7277ec681f3Smrg
7287ec681f3Smrg    /* If colour is written we need to execute */
7297ec681f3Smrg    const struct pan_blend_state *blend = &pipeline->blend.state;
7307ec681f3Smrg    for (unsigned i = 0; i < blend->rt_count; ++i) {
7317ec681f3Smrg       if (blend->rts[i].equation.color_mask)
7327ec681f3Smrg          return true;
7337ec681f3Smrg    }
7347ec681f3Smrg
7357ec681f3Smrg    /* If depth is written and not implied we need to execute.
7367ec681f3Smrg     * TODO: Predicate on Z/S writes being enabled */
7377ec681f3Smrg    return (info->fs.writes_depth || info->fs.writes_stencil);
7387ec681f3Smrg}
7397ec681f3Smrg
7407ec681f3Smrg#define PANVK_DYNAMIC_FS_RSD_MASK \
7417ec681f3Smrg        ((1 << VK_DYNAMIC_STATE_DEPTH_BIAS) | \
7427ec681f3Smrg         (1 << VK_DYNAMIC_STATE_BLEND_CONSTANTS) | \
7437ec681f3Smrg         (1 << VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) | \
7447ec681f3Smrg         (1 << VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) | \
7457ec681f3Smrg         (1 << VK_DYNAMIC_STATE_STENCIL_REFERENCE))
7467ec681f3Smrg
7477ec681f3Smrgstatic void
7487ec681f3Smrgpanvk_pipeline_builder_init_fs_state(struct panvk_pipeline_builder *builder,
7497ec681f3Smrg                                     struct panvk_pipeline *pipeline)
7507ec681f3Smrg{
7517ec681f3Smrg   if (!builder->shaders[MESA_SHADER_FRAGMENT])
7527ec681f3Smrg      return;
7537ec681f3Smrg
7547ec681f3Smrg   pipeline->fs.dynamic_rsd =
7557ec681f3Smrg      pipeline->dynamic_state_mask & PANVK_DYNAMIC_FS_RSD_MASK;
7567ec681f3Smrg   pipeline->fs.address = pipeline->binary_bo->ptr.gpu +
7577ec681f3Smrg                          builder->stages[MESA_SHADER_FRAGMENT].shader_offset;
7587ec681f3Smrg   pipeline->fs.info = builder->shaders[MESA_SHADER_FRAGMENT]->info;
7597ec681f3Smrg   pipeline->fs.rt_mask = builder->active_color_attachments;
7607ec681f3Smrg   pipeline->fs.required = panvk_fs_required(pipeline);
7617ec681f3Smrg}
7627ec681f3Smrg
7637ec681f3Smrgstatic void
7647ec681f3Smrgpanvk_pipeline_update_varying_slot(struct panvk_varyings_info *varyings,
7657ec681f3Smrg                                   gl_shader_stage stage,
7667ec681f3Smrg                                   const struct pan_shader_varying *varying,
7677ec681f3Smrg                                   bool input)
7687ec681f3Smrg{
7697ec681f3Smrg   bool fs = stage == MESA_SHADER_FRAGMENT;
7707ec681f3Smrg   gl_varying_slot loc = varying->location;
7717ec681f3Smrg   enum panvk_varying_buf_id buf_id =
7727ec681f3Smrg      panvk_varying_buf_id(fs, loc);
7737ec681f3Smrg
7747ec681f3Smrg   varyings->stage[stage].loc[varyings->stage[stage].count++] = loc;
7757ec681f3Smrg
7767ec681f3Smrg   if (panvk_varying_is_builtin(stage, loc)) {
7777ec681f3Smrg      varyings->buf_mask |= 1 << buf_id;
7787ec681f3Smrg      return;
7797ec681f3Smrg   }
7807ec681f3Smrg
7817ec681f3Smrg   assert(loc < ARRAY_SIZE(varyings->varying));
7827ec681f3Smrg
7837ec681f3Smrg   enum pipe_format new_fmt = varying->format;
7847ec681f3Smrg   enum pipe_format old_fmt = varyings->varying[loc].format;
7857ec681f3Smrg
7867ec681f3Smrg   BITSET_SET(varyings->active, loc);
7877ec681f3Smrg
7887ec681f3Smrg   /* We expect inputs to either be set by a previous stage or be built
7897ec681f3Smrg    * in, skip the entry if that's not the case, we'll emit a const
7907ec681f3Smrg    * varying returning zero for those entries.
7917ec681f3Smrg    */
7927ec681f3Smrg   if (input && old_fmt == PIPE_FORMAT_NONE)
7937ec681f3Smrg      return;
7947ec681f3Smrg
7957ec681f3Smrg   unsigned new_size = util_format_get_blocksize(new_fmt);
7967ec681f3Smrg   unsigned old_size = util_format_get_blocksize(old_fmt);
7977ec681f3Smrg
7987ec681f3Smrg   if (old_size < new_size)
7997ec681f3Smrg      varyings->varying[loc].format = new_fmt;
8007ec681f3Smrg
8017ec681f3Smrg   varyings->buf_mask |= 1 << buf_id;
8027ec681f3Smrg}
8037ec681f3Smrg
8047ec681f3Smrgstatic void
8057ec681f3Smrgpanvk_pipeline_builder_collect_varyings(struct panvk_pipeline_builder *builder,
8067ec681f3Smrg                                        struct panvk_pipeline *pipeline)
8077ec681f3Smrg{
8087ec681f3Smrg   for (uint32_t s = 0; s < MESA_SHADER_STAGES; s++) {
8097ec681f3Smrg      if (!builder->shaders[s])
8107ec681f3Smrg         continue;
8117ec681f3Smrg
8127ec681f3Smrg      const struct pan_shader_info *info = &builder->shaders[s]->info;
8137ec681f3Smrg
8147ec681f3Smrg      for (unsigned i = 0; i < info->varyings.input_count; i++) {
8157ec681f3Smrg         panvk_pipeline_update_varying_slot(&pipeline->varyings, s,
8167ec681f3Smrg                                            &info->varyings.input[i],
8177ec681f3Smrg                                            true);
8187ec681f3Smrg      }
8197ec681f3Smrg
8207ec681f3Smrg      for (unsigned i = 0; i < info->varyings.output_count; i++) {
8217ec681f3Smrg         panvk_pipeline_update_varying_slot(&pipeline->varyings, s,
8227ec681f3Smrg                                            &info->varyings.output[i],
8237ec681f3Smrg                                            false);
8247ec681f3Smrg      }
8257ec681f3Smrg   }
8267ec681f3Smrg
8277ec681f3Smrg   /* TODO: Xfb */
8287ec681f3Smrg   gl_varying_slot loc;
8297ec681f3Smrg   BITSET_FOREACH_SET(loc, pipeline->varyings.active, VARYING_SLOT_MAX) {
8307ec681f3Smrg      if (pipeline->varyings.varying[loc].format == PIPE_FORMAT_NONE)
8317ec681f3Smrg         continue;
8327ec681f3Smrg
8337ec681f3Smrg      enum panvk_varying_buf_id buf_id =
8347ec681f3Smrg         panvk_varying_buf_id(false, loc);
8357ec681f3Smrg      unsigned buf_idx = panvk_varying_buf_index(&pipeline->varyings, buf_id);
8367ec681f3Smrg      unsigned varying_sz = panvk_varying_size(&pipeline->varyings, loc);
8377ec681f3Smrg
8387ec681f3Smrg      pipeline->varyings.varying[loc].buf = buf_idx;
8397ec681f3Smrg      pipeline->varyings.varying[loc].offset =
8407ec681f3Smrg         pipeline->varyings.buf[buf_idx].stride;
8417ec681f3Smrg      pipeline->varyings.buf[buf_idx].stride += varying_sz;
8427ec681f3Smrg   }
8437ec681f3Smrg}
8447ec681f3Smrg
8457ec681f3Smrgstatic void
8467ec681f3Smrgpanvk_pipeline_builder_parse_vertex_input(struct panvk_pipeline_builder *builder,
8477ec681f3Smrg                                          struct panvk_pipeline *pipeline)
8487ec681f3Smrg{
8497ec681f3Smrg   struct panvk_attribs_info *attribs = &pipeline->attribs;
8507ec681f3Smrg   const VkPipelineVertexInputStateCreateInfo *info =
8517ec681f3Smrg      builder->create_info->pVertexInputState;
8527ec681f3Smrg
8537ec681f3Smrg   for (unsigned i = 0; i < info->vertexBindingDescriptionCount; i++) {
8547ec681f3Smrg      const VkVertexInputBindingDescription *desc =
8557ec681f3Smrg         &info->pVertexBindingDescriptions[i];
8567ec681f3Smrg      attribs->buf_count = MAX2(desc->binding + 1, attribs->buf_count);
8577ec681f3Smrg      attribs->buf[desc->binding].stride = desc->stride;
8587ec681f3Smrg      attribs->buf[desc->binding].special = false;
8597ec681f3Smrg   }
8607ec681f3Smrg
8617ec681f3Smrg   for (unsigned i = 0; i < info->vertexAttributeDescriptionCount; i++) {
8627ec681f3Smrg      const VkVertexInputAttributeDescription *desc =
8637ec681f3Smrg         &info->pVertexAttributeDescriptions[i];
8647ec681f3Smrg      attribs->attrib[desc->location].buf = desc->binding;
8657ec681f3Smrg      attribs->attrib[desc->location].format =
8667ec681f3Smrg         vk_format_to_pipe_format(desc->format);
8677ec681f3Smrg      attribs->attrib[desc->location].offset = desc->offset;
8687ec681f3Smrg   }
8697ec681f3Smrg
8707ec681f3Smrg   const struct pan_shader_info *vs =
8717ec681f3Smrg      &builder->shaders[MESA_SHADER_VERTEX]->info;
8727ec681f3Smrg
8737ec681f3Smrg   if (vs->attribute_count >= PAN_VERTEX_ID) {
8747ec681f3Smrg      attribs->buf[attribs->buf_count].special = true;
8757ec681f3Smrg      attribs->buf[attribs->buf_count].special_id = PAN_VERTEX_ID;
8767ec681f3Smrg      attribs->attrib[PAN_VERTEX_ID].buf = attribs->buf_count++;
8777ec681f3Smrg      attribs->attrib[PAN_VERTEX_ID].format = PIPE_FORMAT_R32_UINT;
8787ec681f3Smrg   }
8797ec681f3Smrg
8807ec681f3Smrg   if (vs->attribute_count >= PAN_INSTANCE_ID) {
8817ec681f3Smrg      attribs->buf[attribs->buf_count].special = true;
8827ec681f3Smrg      attribs->buf[attribs->buf_count].special_id = PAN_INSTANCE_ID;
8837ec681f3Smrg      attribs->attrib[PAN_INSTANCE_ID].buf = attribs->buf_count++;
8847ec681f3Smrg      attribs->attrib[PAN_INSTANCE_ID].format = PIPE_FORMAT_R32_UINT;
8857ec681f3Smrg   }
8867ec681f3Smrg
8877ec681f3Smrg   attribs->attrib_count = MAX2(attribs->attrib_count, vs->attribute_count);
8887ec681f3Smrg}
8897ec681f3Smrg
8907ec681f3Smrgstatic VkResult
8917ec681f3Smrgpanvk_pipeline_builder_build(struct panvk_pipeline_builder *builder,
8927ec681f3Smrg                             struct panvk_pipeline **pipeline)
8937ec681f3Smrg{
8947ec681f3Smrg   VkResult result = panvk_pipeline_builder_create_pipeline(builder, pipeline);
8957ec681f3Smrg   if (result != VK_SUCCESS)
8967ec681f3Smrg      return result;
8977ec681f3Smrg
8987ec681f3Smrg   /* TODO: make those functions return a result and handle errors */
8997ec681f3Smrg   panvk_pipeline_builder_parse_dynamic(builder, *pipeline);
9007ec681f3Smrg   panvk_pipeline_builder_parse_color_blend(builder, *pipeline);
9017ec681f3Smrg   panvk_pipeline_builder_compile_shaders(builder, *pipeline);
9027ec681f3Smrg   panvk_pipeline_builder_collect_varyings(builder, *pipeline);
9037ec681f3Smrg   panvk_pipeline_builder_parse_input_assembly(builder, *pipeline);
9047ec681f3Smrg   panvk_pipeline_builder_parse_multisample(builder, *pipeline);
9057ec681f3Smrg   panvk_pipeline_builder_parse_zs(builder, *pipeline);
9067ec681f3Smrg   panvk_pipeline_builder_parse_rast(builder, *pipeline);
9077ec681f3Smrg   panvk_pipeline_builder_parse_vertex_input(builder, *pipeline);
9087ec681f3Smrg
9097ec681f3Smrg
9107ec681f3Smrg   panvk_pipeline_builder_upload_shaders(builder, *pipeline);
9117ec681f3Smrg   panvk_pipeline_builder_init_fs_state(builder, *pipeline);
9127ec681f3Smrg   panvk_pipeline_builder_alloc_static_state_bo(builder, *pipeline);
9137ec681f3Smrg   panvk_pipeline_builder_init_shaders(builder, *pipeline);
9147ec681f3Smrg   panvk_pipeline_builder_parse_viewport(builder, *pipeline);
9157ec681f3Smrg
9167ec681f3Smrg   return VK_SUCCESS;
9177ec681f3Smrg}
9187ec681f3Smrg
9197ec681f3Smrgstatic void
9207ec681f3Smrgpanvk_pipeline_builder_init_graphics(struct panvk_pipeline_builder *builder,
9217ec681f3Smrg                                     struct panvk_device *dev,
9227ec681f3Smrg                                     struct panvk_pipeline_cache *cache,
9237ec681f3Smrg                                     const VkGraphicsPipelineCreateInfo *create_info,
9247ec681f3Smrg                                     const VkAllocationCallbacks *alloc)
9257ec681f3Smrg{
9267ec681f3Smrg   VK_FROM_HANDLE(panvk_pipeline_layout, layout, create_info->layout);
9277ec681f3Smrg   assert(layout);
9287ec681f3Smrg   *builder = (struct panvk_pipeline_builder) {
9297ec681f3Smrg      .device = dev,
9307ec681f3Smrg      .cache = cache,
9317ec681f3Smrg      .layout = layout,
9327ec681f3Smrg      .create_info = create_info,
9337ec681f3Smrg      .alloc = alloc,
9347ec681f3Smrg   };
9357ec681f3Smrg
9367ec681f3Smrg   builder->rasterizer_discard =
9377ec681f3Smrg      create_info->pRasterizationState->rasterizerDiscardEnable;
9387ec681f3Smrg
9397ec681f3Smrg   if (builder->rasterizer_discard) {
9407ec681f3Smrg      builder->samples = VK_SAMPLE_COUNT_1_BIT;
9417ec681f3Smrg   } else {
9427ec681f3Smrg      builder->samples = create_info->pMultisampleState->rasterizationSamples;
9437ec681f3Smrg
9447ec681f3Smrg      const struct panvk_render_pass *pass = panvk_render_pass_from_handle(create_info->renderPass);
9457ec681f3Smrg      const struct panvk_subpass *subpass = &pass->subpasses[create_info->subpass];
9467ec681f3Smrg
9477ec681f3Smrg      builder->use_depth_stencil_attachment =
9487ec681f3Smrg         subpass->zs_attachment.idx != VK_ATTACHMENT_UNUSED;
9497ec681f3Smrg
9507ec681f3Smrg      assert(subpass->color_count <= create_info->pColorBlendState->attachmentCount);
9517ec681f3Smrg      builder->active_color_attachments = 0;
9527ec681f3Smrg      for (uint32_t i = 0; i < subpass->color_count; i++) {
9537ec681f3Smrg         uint32_t idx = subpass->color_attachments[i].idx;
9547ec681f3Smrg         if (idx == VK_ATTACHMENT_UNUSED)
9557ec681f3Smrg            continue;
9567ec681f3Smrg
9577ec681f3Smrg         builder->active_color_attachments |= 1 << i;
9587ec681f3Smrg         builder->color_attachment_formats[i] = pass->attachments[idx].format;
9597ec681f3Smrg      }
9607ec681f3Smrg   }
9617ec681f3Smrg}
9627ec681f3Smrg
9637ec681f3SmrgVkResult
9647ec681f3Smrgpanvk_per_arch(CreateGraphicsPipelines)(VkDevice device,
9657ec681f3Smrg                                        VkPipelineCache pipelineCache,
9667ec681f3Smrg                                        uint32_t count,
9677ec681f3Smrg                                        const VkGraphicsPipelineCreateInfo *pCreateInfos,
9687ec681f3Smrg                                        const VkAllocationCallbacks *pAllocator,
9697ec681f3Smrg                                        VkPipeline *pPipelines)
9707ec681f3Smrg{
9717ec681f3Smrg   VK_FROM_HANDLE(panvk_device, dev, device);
9727ec681f3Smrg   VK_FROM_HANDLE(panvk_pipeline_cache, cache, pipelineCache);
9737ec681f3Smrg
9747ec681f3Smrg   for (uint32_t i = 0; i < count; i++) {
9757ec681f3Smrg      struct panvk_pipeline_builder builder;
9767ec681f3Smrg      panvk_pipeline_builder_init_graphics(&builder, dev, cache,
9777ec681f3Smrg                                           &pCreateInfos[i], pAllocator);
9787ec681f3Smrg
9797ec681f3Smrg      struct panvk_pipeline *pipeline;
9807ec681f3Smrg      VkResult result = panvk_pipeline_builder_build(&builder, &pipeline);
9817ec681f3Smrg      panvk_pipeline_builder_finish(&builder);
9827ec681f3Smrg
9837ec681f3Smrg      if (result != VK_SUCCESS) {
9847ec681f3Smrg         for (uint32_t j = 0; j < i; j++) {
9857ec681f3Smrg            panvk_DestroyPipeline(device, pPipelines[j], pAllocator);
9867ec681f3Smrg            pPipelines[j] = VK_NULL_HANDLE;
9877ec681f3Smrg         }
9887ec681f3Smrg
9897ec681f3Smrg         return result;
9907ec681f3Smrg      }
9917ec681f3Smrg
9927ec681f3Smrg      pPipelines[i] = panvk_pipeline_to_handle(pipeline);
9937ec681f3Smrg   }
9947ec681f3Smrg
9957ec681f3Smrg   return VK_SUCCESS;
9967ec681f3Smrg}
997