1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2021 Collabora Ltd.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Derived from tu_pipeline.c which is:
5bf215546Sopenharmony_ci * Copyright © 2016 Red Hat.
6bf215546Sopenharmony_ci * Copyright © 2016 Bas Nieuwenhuizen
7bf215546Sopenharmony_ci * Copyright © 2015 Intel Corporation
8bf215546Sopenharmony_ci *
9bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
10bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
11bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
12bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
14bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
17bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
18bf215546Sopenharmony_ci * Software.
19bf215546Sopenharmony_ci *
20bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
27bf215546Sopenharmony_ci */
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "panvk_cs.h"
30bf215546Sopenharmony_ci#include "panvk_private.h"
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "pan_bo.h"
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci#include "nir/nir.h"
35bf215546Sopenharmony_ci#include "nir/nir_builder.h"
36bf215546Sopenharmony_ci#include "spirv/nir_spirv.h"
37bf215546Sopenharmony_ci#include "util/debug.h"
38bf215546Sopenharmony_ci#include "util/mesa-sha1.h"
39bf215546Sopenharmony_ci#include "util/u_atomic.h"
40bf215546Sopenharmony_ci#include "vk_format.h"
41bf215546Sopenharmony_ci#include "vk_util.h"
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci#include "panfrost/util/pan_lower_framebuffer.h"
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_cistruct panvk_pipeline_builder
47bf215546Sopenharmony_ci{
48bf215546Sopenharmony_ci   struct panvk_device *device;
49bf215546Sopenharmony_ci   struct panvk_pipeline_cache *cache;
50bf215546Sopenharmony_ci   const VkAllocationCallbacks *alloc;
51bf215546Sopenharmony_ci   struct {
52bf215546Sopenharmony_ci      const VkGraphicsPipelineCreateInfo *gfx;
53bf215546Sopenharmony_ci      const VkComputePipelineCreateInfo *compute;
54bf215546Sopenharmony_ci   } create_info;
55bf215546Sopenharmony_ci   const struct panvk_pipeline_layout *layout;
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci   struct panvk_shader *shaders[MESA_SHADER_STAGES];
58bf215546Sopenharmony_ci   struct {
59bf215546Sopenharmony_ci      uint32_t shader_offset;
60bf215546Sopenharmony_ci      uint32_t rsd_offset;
61bf215546Sopenharmony_ci   } stages[MESA_SHADER_STAGES];
62bf215546Sopenharmony_ci   uint32_t blend_shader_offsets[MAX_RTS];
63bf215546Sopenharmony_ci   uint32_t shader_total_size;
64bf215546Sopenharmony_ci   uint32_t static_state_size;
65bf215546Sopenharmony_ci   uint32_t vpd_offset;
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   bool rasterizer_discard;
68bf215546Sopenharmony_ci   /* these states are affectd by rasterizer_discard */
69bf215546Sopenharmony_ci   VkSampleCountFlagBits samples;
70bf215546Sopenharmony_ci   bool use_depth_stencil_attachment;
71bf215546Sopenharmony_ci   uint8_t active_color_attachments;
72bf215546Sopenharmony_ci   enum pipe_format color_attachment_formats[MAX_RTS];
73bf215546Sopenharmony_ci};
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_cistatic VkResult
76bf215546Sopenharmony_cipanvk_pipeline_builder_create_pipeline(struct panvk_pipeline_builder *builder,
77bf215546Sopenharmony_ci                                       struct panvk_pipeline **out_pipeline)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   struct panvk_device *dev = builder->device;
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   struct panvk_pipeline *pipeline =
82bf215546Sopenharmony_ci      vk_object_zalloc(&dev->vk, builder->alloc,
83bf215546Sopenharmony_ci                       sizeof(*pipeline), VK_OBJECT_TYPE_PIPELINE);
84bf215546Sopenharmony_ci   if (!pipeline)
85bf215546Sopenharmony_ci      return VK_ERROR_OUT_OF_HOST_MEMORY;
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci   pipeline->layout = builder->layout;
88bf215546Sopenharmony_ci   *out_pipeline = pipeline;
89bf215546Sopenharmony_ci   return VK_SUCCESS;
90bf215546Sopenharmony_ci}
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_cistatic void
93bf215546Sopenharmony_cipanvk_pipeline_builder_finish(struct panvk_pipeline_builder *builder)
94bf215546Sopenharmony_ci{
95bf215546Sopenharmony_ci   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
96bf215546Sopenharmony_ci      if (!builder->shaders[i])
97bf215546Sopenharmony_ci         continue;
98bf215546Sopenharmony_ci      panvk_shader_destroy(builder->device, builder->shaders[i], builder->alloc);
99bf215546Sopenharmony_ci   }
100bf215546Sopenharmony_ci}
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_cistatic bool
103bf215546Sopenharmony_cipanvk_pipeline_static_state(struct panvk_pipeline *pipeline, uint32_t id)
104bf215546Sopenharmony_ci{
105bf215546Sopenharmony_ci   return !(pipeline->dynamic_state_mask & (1 << id));
106bf215546Sopenharmony_ci}
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_cistatic VkResult
109bf215546Sopenharmony_cipanvk_pipeline_builder_compile_shaders(struct panvk_pipeline_builder *builder,
110bf215546Sopenharmony_ci                                       struct panvk_pipeline *pipeline)
111bf215546Sopenharmony_ci{
112bf215546Sopenharmony_ci   const VkPipelineShaderStageCreateInfo *stage_infos[MESA_SHADER_STAGES] = {
113bf215546Sopenharmony_ci      NULL
114bf215546Sopenharmony_ci   };
115bf215546Sopenharmony_ci   const VkPipelineShaderStageCreateInfo *stages =
116bf215546Sopenharmony_ci      builder->create_info.gfx ?
117bf215546Sopenharmony_ci      builder->create_info.gfx->pStages :
118bf215546Sopenharmony_ci      &builder->create_info.compute->stage;
119bf215546Sopenharmony_ci   unsigned stage_count =
120bf215546Sopenharmony_ci      builder->create_info.gfx ? builder->create_info.gfx->stageCount : 1;
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci   for (uint32_t i = 0; i < stage_count; i++) {
123bf215546Sopenharmony_ci      gl_shader_stage stage = vk_to_mesa_shader_stage(stages[i].stage);
124bf215546Sopenharmony_ci      stage_infos[stage] = &stages[i];
125bf215546Sopenharmony_ci   }
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   /* compile shaders in reverse order */
128bf215546Sopenharmony_ci   for (gl_shader_stage stage = MESA_SHADER_STAGES - 1;
129bf215546Sopenharmony_ci        stage > MESA_SHADER_NONE; stage--) {
130bf215546Sopenharmony_ci      const VkPipelineShaderStageCreateInfo *stage_info = stage_infos[stage];
131bf215546Sopenharmony_ci      if (!stage_info)
132bf215546Sopenharmony_ci         continue;
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci      struct panvk_shader *shader;
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci      shader = panvk_per_arch(shader_create)(builder->device, stage, stage_info,
137bf215546Sopenharmony_ci                                             builder->layout,
138bf215546Sopenharmony_ci                                             PANVK_SYSVAL_UBO_INDEX,
139bf215546Sopenharmony_ci                                             &pipeline->blend.state,
140bf215546Sopenharmony_ci                                             panvk_pipeline_static_state(pipeline,
141bf215546Sopenharmony_ci                                                                         VK_DYNAMIC_STATE_BLEND_CONSTANTS),
142bf215546Sopenharmony_ci                                             builder->alloc);
143bf215546Sopenharmony_ci      if (!shader)
144bf215546Sopenharmony_ci         return VK_ERROR_OUT_OF_HOST_MEMORY;
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci      builder->shaders[stage] = shader;
147bf215546Sopenharmony_ci      builder->shader_total_size = ALIGN_POT(builder->shader_total_size, 128);
148bf215546Sopenharmony_ci      builder->stages[stage].shader_offset = builder->shader_total_size;
149bf215546Sopenharmony_ci      builder->shader_total_size +=
150bf215546Sopenharmony_ci         util_dynarray_num_elements(&shader->binary, uint8_t);
151bf215546Sopenharmony_ci   }
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   return VK_SUCCESS;
154bf215546Sopenharmony_ci}
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_cistatic VkResult
157bf215546Sopenharmony_cipanvk_pipeline_builder_upload_shaders(struct panvk_pipeline_builder *builder,
158bf215546Sopenharmony_ci                                      struct panvk_pipeline *pipeline)
159bf215546Sopenharmony_ci{
160bf215546Sopenharmony_ci   /* In some cases, the optimized shader is empty. Don't bother allocating
161bf215546Sopenharmony_ci    * anything in this case.
162bf215546Sopenharmony_ci    */
163bf215546Sopenharmony_ci   if (builder->shader_total_size == 0)
164bf215546Sopenharmony_ci      return VK_SUCCESS;
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   struct panfrost_bo *bin_bo =
167bf215546Sopenharmony_ci      panfrost_bo_create(&builder->device->physical_device->pdev,
168bf215546Sopenharmony_ci                         builder->shader_total_size, PAN_BO_EXECUTE,
169bf215546Sopenharmony_ci                         "Shader");
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   pipeline->binary_bo = bin_bo;
172bf215546Sopenharmony_ci   panfrost_bo_mmap(bin_bo);
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
175bf215546Sopenharmony_ci      const struct panvk_shader *shader = builder->shaders[i];
176bf215546Sopenharmony_ci      if (!shader)
177bf215546Sopenharmony_ci         continue;
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_ci      memcpy(pipeline->binary_bo->ptr.cpu + builder->stages[i].shader_offset,
180bf215546Sopenharmony_ci             util_dynarray_element(&shader->binary, uint8_t, 0),
181bf215546Sopenharmony_ci             util_dynarray_num_elements(&shader->binary, uint8_t));
182bf215546Sopenharmony_ci   }
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   return VK_SUCCESS;
185bf215546Sopenharmony_ci}
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_cistatic bool
188bf215546Sopenharmony_cipanvk_pipeline_static_sysval(struct panvk_pipeline *pipeline,
189bf215546Sopenharmony_ci                             unsigned id)
190bf215546Sopenharmony_ci{
191bf215546Sopenharmony_ci   switch (id) {
192bf215546Sopenharmony_ci   case PAN_SYSVAL_VIEWPORT_SCALE:
193bf215546Sopenharmony_ci   case PAN_SYSVAL_VIEWPORT_OFFSET:
194bf215546Sopenharmony_ci      return panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT);
195bf215546Sopenharmony_ci   default:
196bf215546Sopenharmony_ci      return false;
197bf215546Sopenharmony_ci   }
198bf215546Sopenharmony_ci}
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_cistatic void
201bf215546Sopenharmony_cipanvk_pipeline_builder_alloc_static_state_bo(struct panvk_pipeline_builder *builder,
202bf215546Sopenharmony_ci                                             struct panvk_pipeline *pipeline)
203bf215546Sopenharmony_ci{
204bf215546Sopenharmony_ci   struct panfrost_device *pdev =
205bf215546Sopenharmony_ci      &builder->device->physical_device->pdev;
206bf215546Sopenharmony_ci   unsigned bo_size = 0;
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
209bf215546Sopenharmony_ci      const struct panvk_shader *shader = builder->shaders[i];
210bf215546Sopenharmony_ci      if (!shader && i != MESA_SHADER_FRAGMENT)
211bf215546Sopenharmony_ci         continue;
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci      if (pipeline->fs.dynamic_rsd && i == MESA_SHADER_FRAGMENT)
214bf215546Sopenharmony_ci         continue;
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci      bo_size = ALIGN_POT(bo_size, pan_alignment(RENDERER_STATE));
217bf215546Sopenharmony_ci      builder->stages[i].rsd_offset = bo_size;
218bf215546Sopenharmony_ci      bo_size += pan_size(RENDERER_STATE);
219bf215546Sopenharmony_ci      if (i == MESA_SHADER_FRAGMENT)
220bf215546Sopenharmony_ci         bo_size += pan_size(BLEND) * MAX2(pipeline->blend.state.rt_count, 1);
221bf215546Sopenharmony_ci   }
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci   if (builder->create_info.gfx &&
224bf215546Sopenharmony_ci       panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT) &&
225bf215546Sopenharmony_ci       panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_SCISSOR)) {
226bf215546Sopenharmony_ci      bo_size = ALIGN_POT(bo_size, pan_alignment(VIEWPORT));
227bf215546Sopenharmony_ci      builder->vpd_offset = bo_size;
228bf215546Sopenharmony_ci      bo_size += pan_size(VIEWPORT);
229bf215546Sopenharmony_ci   }
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   if (bo_size) {
232bf215546Sopenharmony_ci      pipeline->state_bo =
233bf215546Sopenharmony_ci         panfrost_bo_create(pdev, bo_size, 0, "Pipeline descriptors");
234bf215546Sopenharmony_ci      panfrost_bo_mmap(pipeline->state_bo);
235bf215546Sopenharmony_ci   }
236bf215546Sopenharmony_ci}
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_cistatic void
239bf215546Sopenharmony_cipanvk_pipeline_builder_init_sysvals(struct panvk_pipeline_builder *builder,
240bf215546Sopenharmony_ci                                    struct panvk_pipeline *pipeline,
241bf215546Sopenharmony_ci                                    gl_shader_stage stage)
242bf215546Sopenharmony_ci{
243bf215546Sopenharmony_ci   const struct panvk_shader *shader = builder->shaders[stage];
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   pipeline->sysvals[stage].ids = shader->info.sysvals;
246bf215546Sopenharmony_ci   pipeline->sysvals[stage].ubo_idx = shader->sysval_ubo;
247bf215546Sopenharmony_ci}
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_cistatic void
250bf215546Sopenharmony_cipanvk_pipeline_builder_init_shaders(struct panvk_pipeline_builder *builder,
251bf215546Sopenharmony_ci                                    struct panvk_pipeline *pipeline)
252bf215546Sopenharmony_ci{
253bf215546Sopenharmony_ci   for (uint32_t i = 0; i < MESA_SHADER_STAGES; i++) {
254bf215546Sopenharmony_ci      const struct panvk_shader *shader = builder->shaders[i];
255bf215546Sopenharmony_ci      if (!shader)
256bf215546Sopenharmony_ci         continue;
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci      pipeline->tls_size = MAX2(pipeline->tls_size, shader->info.tls_size);
259bf215546Sopenharmony_ci      pipeline->wls_size = MAX2(pipeline->wls_size, shader->info.wls_size);
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci      if (shader->has_img_access)
262bf215546Sopenharmony_ci         pipeline->img_access_mask |= BITFIELD_BIT(i);
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci      if (i == MESA_SHADER_VERTEX && shader->info.vs.writes_point_size) {
265bf215546Sopenharmony_ci         VkPrimitiveTopology topology =
266bf215546Sopenharmony_ci            builder->create_info.gfx->pInputAssemblyState->topology;
267bf215546Sopenharmony_ci         bool points = (topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_ci         /* Even if the vertex shader writes point size, we only consider the
270bf215546Sopenharmony_ci          * pipeline to write point size when we're actually drawing points.
271bf215546Sopenharmony_ci          * Otherwise the point size write would conflict with wide lines.
272bf215546Sopenharmony_ci          */
273bf215546Sopenharmony_ci         pipeline->ia.writes_point_size = points;
274bf215546Sopenharmony_ci      }
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci      mali_ptr shader_ptr = 0;
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci      /* Handle empty shaders gracefully */
279bf215546Sopenharmony_ci      if (util_dynarray_num_elements(&builder->shaders[i]->binary, uint8_t)) {
280bf215546Sopenharmony_ci         shader_ptr = pipeline->binary_bo->ptr.gpu +
281bf215546Sopenharmony_ci                      builder->stages[i].shader_offset;
282bf215546Sopenharmony_ci      }
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci      if (i != MESA_SHADER_FRAGMENT) {
285bf215546Sopenharmony_ci         void *rsd = pipeline->state_bo->ptr.cpu + builder->stages[i].rsd_offset;
286bf215546Sopenharmony_ci         mali_ptr gpu_rsd = pipeline->state_bo->ptr.gpu + builder->stages[i].rsd_offset;
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_ci         panvk_per_arch(emit_non_fs_rsd)(builder->device, &shader->info, shader_ptr, rsd);
289bf215546Sopenharmony_ci         pipeline->rsds[i] = gpu_rsd;
290bf215546Sopenharmony_ci      }
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci      panvk_pipeline_builder_init_sysvals(builder, pipeline, i);
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci      if (i == MESA_SHADER_COMPUTE)
295bf215546Sopenharmony_ci         pipeline->cs.local_size = shader->local_size;
296bf215546Sopenharmony_ci   }
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci   if (builder->create_info.gfx && !pipeline->fs.dynamic_rsd) {
299bf215546Sopenharmony_ci      void *rsd = pipeline->state_bo->ptr.cpu + builder->stages[MESA_SHADER_FRAGMENT].rsd_offset;
300bf215546Sopenharmony_ci      mali_ptr gpu_rsd = pipeline->state_bo->ptr.gpu + builder->stages[MESA_SHADER_FRAGMENT].rsd_offset;
301bf215546Sopenharmony_ci      void *bd = rsd + pan_size(RENDERER_STATE);
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci      panvk_per_arch(emit_base_fs_rsd)(builder->device, pipeline, rsd);
304bf215546Sopenharmony_ci      for (unsigned rt = 0; rt < pipeline->blend.state.rt_count; rt++) {
305bf215546Sopenharmony_ci         panvk_per_arch(emit_blend)(builder->device, pipeline, rt, bd);
306bf215546Sopenharmony_ci         bd += pan_size(BLEND);
307bf215546Sopenharmony_ci      }
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci      pipeline->rsds[MESA_SHADER_FRAGMENT] = gpu_rsd;
310bf215546Sopenharmony_ci   } else if (builder->create_info.gfx) {
311bf215546Sopenharmony_ci      panvk_per_arch(emit_base_fs_rsd)(builder->device, pipeline, &pipeline->fs.rsd_template);
312bf215546Sopenharmony_ci      for (unsigned rt = 0; rt < MAX2(pipeline->blend.state.rt_count, 1); rt++) {
313bf215546Sopenharmony_ci         panvk_per_arch(emit_blend)(builder->device, pipeline, rt,
314bf215546Sopenharmony_ci                                    &pipeline->blend.bd_template[rt]);
315bf215546Sopenharmony_ci      }
316bf215546Sopenharmony_ci   }
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   pipeline->num_ubos = PANVK_NUM_BUILTIN_UBOS +
319bf215546Sopenharmony_ci                        builder->layout->num_ubos +
320bf215546Sopenharmony_ci                        builder->layout->num_dyn_ubos;
321bf215546Sopenharmony_ci}
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_cistatic void
325bf215546Sopenharmony_cipanvk_pipeline_builder_parse_viewport(struct panvk_pipeline_builder *builder,
326bf215546Sopenharmony_ci                                      struct panvk_pipeline *pipeline)
327bf215546Sopenharmony_ci{
328bf215546Sopenharmony_ci   /* The spec says:
329bf215546Sopenharmony_ci    *
330bf215546Sopenharmony_ci    *    pViewportState is a pointer to an instance of the
331bf215546Sopenharmony_ci    *    VkPipelineViewportStateCreateInfo structure, and is ignored if the
332bf215546Sopenharmony_ci    *    pipeline has rasterization disabled.
333bf215546Sopenharmony_ci    */
334bf215546Sopenharmony_ci   if (!builder->rasterizer_discard &&
335bf215546Sopenharmony_ci       panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT) &&
336bf215546Sopenharmony_ci       panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_SCISSOR)) {
337bf215546Sopenharmony_ci      void *vpd = pipeline->state_bo->ptr.cpu + builder->vpd_offset;
338bf215546Sopenharmony_ci      panvk_per_arch(emit_viewport)(builder->create_info.gfx->pViewportState->pViewports,
339bf215546Sopenharmony_ci                                    builder->create_info.gfx->pViewportState->pScissors,
340bf215546Sopenharmony_ci                                    vpd);
341bf215546Sopenharmony_ci      pipeline->vpd = pipeline->state_bo->ptr.gpu +
342bf215546Sopenharmony_ci                      builder->vpd_offset;
343bf215546Sopenharmony_ci   }
344bf215546Sopenharmony_ci   if (panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_VIEWPORT))
345bf215546Sopenharmony_ci      pipeline->viewport = builder->create_info.gfx->pViewportState->pViewports[0];
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   if (panvk_pipeline_static_state(pipeline, VK_DYNAMIC_STATE_SCISSOR))
348bf215546Sopenharmony_ci      pipeline->scissor = builder->create_info.gfx->pViewportState->pScissors[0];
349bf215546Sopenharmony_ci}
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_cistatic void
352bf215546Sopenharmony_cipanvk_pipeline_builder_parse_dynamic(struct panvk_pipeline_builder *builder,
353bf215546Sopenharmony_ci                                     struct panvk_pipeline *pipeline)
354bf215546Sopenharmony_ci{
355bf215546Sopenharmony_ci   const VkPipelineDynamicStateCreateInfo *dynamic_info =
356bf215546Sopenharmony_ci      builder->create_info.gfx->pDynamicState;
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci   if (!dynamic_info)
359bf215546Sopenharmony_ci      return;
360bf215546Sopenharmony_ci
361bf215546Sopenharmony_ci   for (uint32_t i = 0; i < dynamic_info->dynamicStateCount; i++) {
362bf215546Sopenharmony_ci      VkDynamicState state = dynamic_info->pDynamicStates[i];
363bf215546Sopenharmony_ci      switch (state) {
364bf215546Sopenharmony_ci      case VK_DYNAMIC_STATE_VIEWPORT ... VK_DYNAMIC_STATE_STENCIL_REFERENCE:
365bf215546Sopenharmony_ci         pipeline->dynamic_state_mask |= 1 << state;
366bf215546Sopenharmony_ci         break;
367bf215546Sopenharmony_ci      default:
368bf215546Sopenharmony_ci         unreachable("unsupported dynamic state");
369bf215546Sopenharmony_ci      }
370bf215546Sopenharmony_ci   }
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci}
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_cistatic enum mali_draw_mode
375bf215546Sopenharmony_citranslate_prim_topology(VkPrimitiveTopology in)
376bf215546Sopenharmony_ci{
377bf215546Sopenharmony_ci   switch (in) {
378bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
379bf215546Sopenharmony_ci      return MALI_DRAW_MODE_POINTS;
380bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
381bf215546Sopenharmony_ci      return MALI_DRAW_MODE_LINES;
382bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
383bf215546Sopenharmony_ci      return MALI_DRAW_MODE_LINE_STRIP;
384bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
385bf215546Sopenharmony_ci      return MALI_DRAW_MODE_TRIANGLES;
386bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
387bf215546Sopenharmony_ci      return MALI_DRAW_MODE_TRIANGLE_STRIP;
388bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
389bf215546Sopenharmony_ci      return MALI_DRAW_MODE_TRIANGLE_FAN;
390bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
391bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
392bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
393bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
394bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
395bf215546Sopenharmony_ci   default:
396bf215546Sopenharmony_ci      unreachable("Invalid primitive type");
397bf215546Sopenharmony_ci   }
398bf215546Sopenharmony_ci}
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_cistatic void
401bf215546Sopenharmony_cipanvk_pipeline_builder_parse_input_assembly(struct panvk_pipeline_builder *builder,
402bf215546Sopenharmony_ci                                            struct panvk_pipeline *pipeline)
403bf215546Sopenharmony_ci{
404bf215546Sopenharmony_ci   pipeline->ia.primitive_restart =
405bf215546Sopenharmony_ci      builder->create_info.gfx->pInputAssemblyState->primitiveRestartEnable;
406bf215546Sopenharmony_ci   pipeline->ia.topology =
407bf215546Sopenharmony_ci      translate_prim_topology(builder->create_info.gfx->pInputAssemblyState->topology);
408bf215546Sopenharmony_ci}
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_cistatic enum pipe_logicop
411bf215546Sopenharmony_citranslate_logicop(VkLogicOp in)
412bf215546Sopenharmony_ci{
413bf215546Sopenharmony_ci   switch (in) {
414bf215546Sopenharmony_ci   case VK_LOGIC_OP_CLEAR: return PIPE_LOGICOP_CLEAR;
415bf215546Sopenharmony_ci   case VK_LOGIC_OP_AND: return PIPE_LOGICOP_AND;
416bf215546Sopenharmony_ci   case VK_LOGIC_OP_AND_REVERSE: return PIPE_LOGICOP_AND_REVERSE;
417bf215546Sopenharmony_ci   case VK_LOGIC_OP_COPY: return PIPE_LOGICOP_COPY;
418bf215546Sopenharmony_ci   case VK_LOGIC_OP_AND_INVERTED: return PIPE_LOGICOP_AND_INVERTED;
419bf215546Sopenharmony_ci   case VK_LOGIC_OP_NO_OP: return PIPE_LOGICOP_NOOP;
420bf215546Sopenharmony_ci   case VK_LOGIC_OP_XOR: return PIPE_LOGICOP_XOR;
421bf215546Sopenharmony_ci   case VK_LOGIC_OP_OR: return PIPE_LOGICOP_OR;
422bf215546Sopenharmony_ci   case VK_LOGIC_OP_NOR: return PIPE_LOGICOP_NOR;
423bf215546Sopenharmony_ci   case VK_LOGIC_OP_EQUIVALENT: return PIPE_LOGICOP_EQUIV;
424bf215546Sopenharmony_ci   case VK_LOGIC_OP_INVERT: return PIPE_LOGICOP_INVERT;
425bf215546Sopenharmony_ci   case VK_LOGIC_OP_OR_REVERSE: return PIPE_LOGICOP_OR_REVERSE;
426bf215546Sopenharmony_ci   case VK_LOGIC_OP_COPY_INVERTED: return PIPE_LOGICOP_COPY_INVERTED;
427bf215546Sopenharmony_ci   case VK_LOGIC_OP_OR_INVERTED: return PIPE_LOGICOP_OR_INVERTED;
428bf215546Sopenharmony_ci   case VK_LOGIC_OP_NAND: return PIPE_LOGICOP_NAND;
429bf215546Sopenharmony_ci   case VK_LOGIC_OP_SET: return PIPE_LOGICOP_SET;
430bf215546Sopenharmony_ci   default: unreachable("Invalid logicop");
431bf215546Sopenharmony_ci   }
432bf215546Sopenharmony_ci}
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_cistatic enum blend_func
435bf215546Sopenharmony_citranslate_blend_op(VkBlendOp in)
436bf215546Sopenharmony_ci{
437bf215546Sopenharmony_ci   switch (in) {
438bf215546Sopenharmony_ci   case VK_BLEND_OP_ADD: return BLEND_FUNC_ADD;
439bf215546Sopenharmony_ci   case VK_BLEND_OP_SUBTRACT: return BLEND_FUNC_SUBTRACT;
440bf215546Sopenharmony_ci   case VK_BLEND_OP_REVERSE_SUBTRACT: return BLEND_FUNC_REVERSE_SUBTRACT;
441bf215546Sopenharmony_ci   case VK_BLEND_OP_MIN: return BLEND_FUNC_MIN;
442bf215546Sopenharmony_ci   case VK_BLEND_OP_MAX: return BLEND_FUNC_MAX;
443bf215546Sopenharmony_ci   default: unreachable("Invalid blend op");
444bf215546Sopenharmony_ci   }
445bf215546Sopenharmony_ci}
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_cistatic enum blend_factor
448bf215546Sopenharmony_citranslate_blend_factor(VkBlendFactor in, bool dest_has_alpha)
449bf215546Sopenharmony_ci{
450bf215546Sopenharmony_ci   switch (in) {
451bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ZERO:
452bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE:
453bf215546Sopenharmony_ci      return BLEND_FACTOR_ZERO;
454bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC_COLOR:
455bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
456bf215546Sopenharmony_ci      return BLEND_FACTOR_SRC_COLOR;
457bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_DST_COLOR:
458bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
459bf215546Sopenharmony_ci      return BLEND_FACTOR_DST_COLOR;
460bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC_ALPHA:
461bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
462bf215546Sopenharmony_ci      return BLEND_FACTOR_SRC_ALPHA;
463bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_DST_ALPHA:
464bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
465bf215546Sopenharmony_ci      return dest_has_alpha ? BLEND_FACTOR_DST_ALPHA : BLEND_FACTOR_ZERO;
466bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_CONSTANT_COLOR:
467bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
468bf215546Sopenharmony_ci      return BLEND_FACTOR_CONSTANT_COLOR;
469bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_CONSTANT_ALPHA:
470bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
471bf215546Sopenharmony_ci      return BLEND_FACTOR_CONSTANT_ALPHA;
472bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC1_COLOR:
473bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
474bf215546Sopenharmony_ci      return BLEND_FACTOR_SRC1_COLOR;
475bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC1_ALPHA:
476bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
477bf215546Sopenharmony_ci      return BLEND_FACTOR_SRC1_ALPHA;
478bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE:
479bf215546Sopenharmony_ci      return BLEND_FACTOR_SRC_ALPHA_SATURATE;
480bf215546Sopenharmony_ci   default: unreachable("Invalid blend factor");
481bf215546Sopenharmony_ci   }
482bf215546Sopenharmony_ci}
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_cistatic bool
485bf215546Sopenharmony_ciinverted_blend_factor(VkBlendFactor in, bool dest_has_alpha)
486bf215546Sopenharmony_ci{
487bf215546Sopenharmony_ci   switch (in) {
488bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE:
489bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
490bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
491bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
492bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
493bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
494bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
495bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
496bf215546Sopenharmony_ci      return true;
497bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
498bf215546Sopenharmony_ci      return dest_has_alpha ? true : false;
499bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_DST_ALPHA:
500bf215546Sopenharmony_ci      return !dest_has_alpha ? true : false;
501bf215546Sopenharmony_ci   default:
502bf215546Sopenharmony_ci      return false;
503bf215546Sopenharmony_ci   }
504bf215546Sopenharmony_ci}
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_cibool
507bf215546Sopenharmony_cipanvk_per_arch(blend_needs_lowering)(const struct panfrost_device *dev,
508bf215546Sopenharmony_ci                                     const struct pan_blend_state *state,
509bf215546Sopenharmony_ci                                     unsigned rt)
510bf215546Sopenharmony_ci{
511bf215546Sopenharmony_ci   /* LogicOp requires a blend shader */
512bf215546Sopenharmony_ci   if (state->logicop_enable)
513bf215546Sopenharmony_ci      return true;
514bf215546Sopenharmony_ci
515bf215546Sopenharmony_ci   /* Not all formats can be blended by fixed-function hardware */
516bf215546Sopenharmony_ci   if (!panfrost_blendable_formats_v7[state->rts[rt].format].internal)
517bf215546Sopenharmony_ci      return true;
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci   unsigned constant_mask = pan_blend_constant_mask(state->rts[rt].equation);
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_ci   /* v6 doesn't support blend constants in FF blend equations.
522bf215546Sopenharmony_ci    * v7 only uses the constant from RT 0 (TODO: what if it's the same
523bf215546Sopenharmony_ci    * constant? or a constant is shared?)
524bf215546Sopenharmony_ci    */
525bf215546Sopenharmony_ci   if (constant_mask && (PAN_ARCH == 6 || (PAN_ARCH == 7 && rt > 0)))
526bf215546Sopenharmony_ci      return true;
527bf215546Sopenharmony_ci
528bf215546Sopenharmony_ci   if (!pan_blend_is_homogenous_constant(constant_mask, state->constants))
529bf215546Sopenharmony_ci      return true;
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   bool supports_2src = pan_blend_supports_2src(dev->arch);
532bf215546Sopenharmony_ci   return !pan_blend_can_fixed_function(state->rts[rt].equation, supports_2src);
533bf215546Sopenharmony_ci}
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_cistatic void
536bf215546Sopenharmony_cipanvk_pipeline_builder_parse_color_blend(struct panvk_pipeline_builder *builder,
537bf215546Sopenharmony_ci                                         struct panvk_pipeline *pipeline)
538bf215546Sopenharmony_ci{
539bf215546Sopenharmony_ci   struct panfrost_device *pdev = &builder->device->physical_device->pdev;
540bf215546Sopenharmony_ci   pipeline->blend.state.logicop_enable =
541bf215546Sopenharmony_ci      builder->create_info.gfx->pColorBlendState->logicOpEnable;
542bf215546Sopenharmony_ci   pipeline->blend.state.logicop_func =
543bf215546Sopenharmony_ci      translate_logicop(builder->create_info.gfx->pColorBlendState->logicOp);
544bf215546Sopenharmony_ci   pipeline->blend.state.rt_count = util_last_bit(builder->active_color_attachments);
545bf215546Sopenharmony_ci   memcpy(pipeline->blend.state.constants,
546bf215546Sopenharmony_ci          builder->create_info.gfx->pColorBlendState->blendConstants,
547bf215546Sopenharmony_ci          sizeof(pipeline->blend.state.constants));
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci   for (unsigned i = 0; i < pipeline->blend.state.rt_count; i++) {
550bf215546Sopenharmony_ci      const VkPipelineColorBlendAttachmentState *in =
551bf215546Sopenharmony_ci         &builder->create_info.gfx->pColorBlendState->pAttachments[i];
552bf215546Sopenharmony_ci      struct pan_blend_rt_state *out = &pipeline->blend.state.rts[i];
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ci      out->format = builder->color_attachment_formats[i];
555bf215546Sopenharmony_ci
556bf215546Sopenharmony_ci      bool dest_has_alpha = util_format_has_alpha(out->format);
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci      out->nr_samples = builder->create_info.gfx->pMultisampleState->rasterizationSamples;
559bf215546Sopenharmony_ci      out->equation.blend_enable = in->blendEnable;
560bf215546Sopenharmony_ci      out->equation.color_mask = in->colorWriteMask;
561bf215546Sopenharmony_ci      out->equation.rgb_func = translate_blend_op(in->colorBlendOp);
562bf215546Sopenharmony_ci      out->equation.rgb_src_factor = translate_blend_factor(in->srcColorBlendFactor, dest_has_alpha);
563bf215546Sopenharmony_ci      out->equation.rgb_invert_src_factor = inverted_blend_factor(in->srcColorBlendFactor, dest_has_alpha);
564bf215546Sopenharmony_ci      out->equation.rgb_dst_factor = translate_blend_factor(in->dstColorBlendFactor, dest_has_alpha);
565bf215546Sopenharmony_ci      out->equation.rgb_invert_dst_factor = inverted_blend_factor(in->dstColorBlendFactor, dest_has_alpha);
566bf215546Sopenharmony_ci      out->equation.alpha_func = translate_blend_op(in->alphaBlendOp);
567bf215546Sopenharmony_ci      out->equation.alpha_src_factor = translate_blend_factor(in->srcAlphaBlendFactor, dest_has_alpha);
568bf215546Sopenharmony_ci      out->equation.alpha_invert_src_factor = inverted_blend_factor(in->srcAlphaBlendFactor, dest_has_alpha);
569bf215546Sopenharmony_ci      out->equation.alpha_dst_factor = translate_blend_factor(in->dstAlphaBlendFactor, dest_has_alpha);
570bf215546Sopenharmony_ci      out->equation.alpha_invert_dst_factor = inverted_blend_factor(in->dstAlphaBlendFactor, dest_has_alpha);
571bf215546Sopenharmony_ci
572bf215546Sopenharmony_ci      pipeline->blend.reads_dest |= pan_blend_reads_dest(out->equation);
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci      unsigned constant_mask =
575bf215546Sopenharmony_ci         panvk_per_arch(blend_needs_lowering)(pdev, &pipeline->blend.state, i) ?
576bf215546Sopenharmony_ci         0 : pan_blend_constant_mask(out->equation);
577bf215546Sopenharmony_ci      pipeline->blend.constant[i].index = ffs(constant_mask) - 1;
578bf215546Sopenharmony_ci      if (constant_mask) {
579bf215546Sopenharmony_ci         /* On Bifrost, the blend constant is expressed with a UNORM of the
580bf215546Sopenharmony_ci          * size of the target format. The value is then shifted such that
581bf215546Sopenharmony_ci          * used bits are in the MSB. Here we calculate the factor at pipeline
582bf215546Sopenharmony_ci          * creation time so we only have to do a
583bf215546Sopenharmony_ci          *   hw_constant = float_constant * factor;
584bf215546Sopenharmony_ci          * at descriptor emission time.
585bf215546Sopenharmony_ci          */
586bf215546Sopenharmony_ci         const struct util_format_description *format_desc =
587bf215546Sopenharmony_ci            util_format_description(out->format);
588bf215546Sopenharmony_ci         unsigned chan_size = 0;
589bf215546Sopenharmony_ci         for (unsigned c = 0; c < format_desc->nr_channels; c++)
590bf215546Sopenharmony_ci            chan_size = MAX2(format_desc->channel[c].size, chan_size);
591bf215546Sopenharmony_ci         pipeline->blend.constant[i].bifrost_factor =
592bf215546Sopenharmony_ci            ((1 << chan_size) - 1) << (16 - chan_size);
593bf215546Sopenharmony_ci      }
594bf215546Sopenharmony_ci   }
595bf215546Sopenharmony_ci}
596bf215546Sopenharmony_ci
597bf215546Sopenharmony_cistatic void
598bf215546Sopenharmony_cipanvk_pipeline_builder_parse_multisample(struct panvk_pipeline_builder *builder,
599bf215546Sopenharmony_ci                                         struct panvk_pipeline *pipeline)
600bf215546Sopenharmony_ci{
601bf215546Sopenharmony_ci   unsigned nr_samples =
602bf215546Sopenharmony_ci      MAX2(builder->create_info.gfx->pMultisampleState->rasterizationSamples, 1);
603bf215546Sopenharmony_ci
604bf215546Sopenharmony_ci   pipeline->ms.rast_samples =
605bf215546Sopenharmony_ci      builder->create_info.gfx->pMultisampleState->rasterizationSamples;
606bf215546Sopenharmony_ci   pipeline->ms.sample_mask =
607bf215546Sopenharmony_ci      builder->create_info.gfx->pMultisampleState->pSampleMask ?
608bf215546Sopenharmony_ci      builder->create_info.gfx->pMultisampleState->pSampleMask[0] : UINT16_MAX;
609bf215546Sopenharmony_ci   pipeline->ms.min_samples =
610bf215546Sopenharmony_ci      MAX2(builder->create_info.gfx->pMultisampleState->minSampleShading * nr_samples, 1);
611bf215546Sopenharmony_ci}
612bf215546Sopenharmony_ci
613bf215546Sopenharmony_cistatic enum mali_stencil_op
614bf215546Sopenharmony_citranslate_stencil_op(VkStencilOp in)
615bf215546Sopenharmony_ci{
616bf215546Sopenharmony_ci   switch (in) {
617bf215546Sopenharmony_ci   case VK_STENCIL_OP_KEEP: return MALI_STENCIL_OP_KEEP;
618bf215546Sopenharmony_ci   case VK_STENCIL_OP_ZERO: return MALI_STENCIL_OP_ZERO;
619bf215546Sopenharmony_ci   case VK_STENCIL_OP_REPLACE: return MALI_STENCIL_OP_REPLACE;
620bf215546Sopenharmony_ci   case VK_STENCIL_OP_INCREMENT_AND_CLAMP: return MALI_STENCIL_OP_INCR_SAT;
621bf215546Sopenharmony_ci   case VK_STENCIL_OP_DECREMENT_AND_CLAMP: return MALI_STENCIL_OP_DECR_SAT;
622bf215546Sopenharmony_ci   case VK_STENCIL_OP_INCREMENT_AND_WRAP: return MALI_STENCIL_OP_INCR_WRAP;
623bf215546Sopenharmony_ci   case VK_STENCIL_OP_DECREMENT_AND_WRAP: return MALI_STENCIL_OP_DECR_WRAP;
624bf215546Sopenharmony_ci   case VK_STENCIL_OP_INVERT: return MALI_STENCIL_OP_INVERT;
625bf215546Sopenharmony_ci   default: unreachable("Invalid stencil op");
626bf215546Sopenharmony_ci   }
627bf215546Sopenharmony_ci}
628bf215546Sopenharmony_ci
629bf215546Sopenharmony_cistatic void
630bf215546Sopenharmony_cipanvk_pipeline_builder_parse_zs(struct panvk_pipeline_builder *builder,
631bf215546Sopenharmony_ci                                struct panvk_pipeline *pipeline)
632bf215546Sopenharmony_ci{
633bf215546Sopenharmony_ci   if (!builder->use_depth_stencil_attachment)
634bf215546Sopenharmony_ci      return;
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   pipeline->zs.z_test = builder->create_info.gfx->pDepthStencilState->depthTestEnable;
637bf215546Sopenharmony_ci
638bf215546Sopenharmony_ci   /* The Vulkan spec says:
639bf215546Sopenharmony_ci    *
640bf215546Sopenharmony_ci    *    depthWriteEnable controls whether depth writes are enabled when
641bf215546Sopenharmony_ci    *    depthTestEnable is VK_TRUE. Depth writes are always disabled when
642bf215546Sopenharmony_ci    *    depthTestEnable is VK_FALSE.
643bf215546Sopenharmony_ci    *
644bf215546Sopenharmony_ci    * The hardware does not make this distinction, though, so we AND in the
645bf215546Sopenharmony_ci    * condition ourselves.
646bf215546Sopenharmony_ci    */
647bf215546Sopenharmony_ci   pipeline->zs.z_write = pipeline->zs.z_test &&
648bf215546Sopenharmony_ci      builder->create_info.gfx->pDepthStencilState->depthWriteEnable;
649bf215546Sopenharmony_ci
650bf215546Sopenharmony_ci   pipeline->zs.z_compare_func =
651bf215546Sopenharmony_ci      panvk_per_arch(translate_compare_func)(builder->create_info.gfx->pDepthStencilState->depthCompareOp);
652bf215546Sopenharmony_ci   pipeline->zs.s_test = builder->create_info.gfx->pDepthStencilState->stencilTestEnable;
653bf215546Sopenharmony_ci   pipeline->zs.s_front.fail_op =
654bf215546Sopenharmony_ci      translate_stencil_op(builder->create_info.gfx->pDepthStencilState->front.failOp);
655bf215546Sopenharmony_ci   pipeline->zs.s_front.pass_op =
656bf215546Sopenharmony_ci      translate_stencil_op(builder->create_info.gfx->pDepthStencilState->front.passOp);
657bf215546Sopenharmony_ci   pipeline->zs.s_front.z_fail_op =
658bf215546Sopenharmony_ci      translate_stencil_op(builder->create_info.gfx->pDepthStencilState->front.depthFailOp);
659bf215546Sopenharmony_ci   pipeline->zs.s_front.compare_func =
660bf215546Sopenharmony_ci      panvk_per_arch(translate_compare_func)(builder->create_info.gfx->pDepthStencilState->front.compareOp);
661bf215546Sopenharmony_ci   pipeline->zs.s_front.compare_mask =
662bf215546Sopenharmony_ci      builder->create_info.gfx->pDepthStencilState->front.compareMask;
663bf215546Sopenharmony_ci   pipeline->zs.s_front.write_mask =
664bf215546Sopenharmony_ci      builder->create_info.gfx->pDepthStencilState->front.writeMask;
665bf215546Sopenharmony_ci   pipeline->zs.s_front.ref =
666bf215546Sopenharmony_ci      builder->create_info.gfx->pDepthStencilState->front.reference;
667bf215546Sopenharmony_ci   pipeline->zs.s_back.fail_op =
668bf215546Sopenharmony_ci      translate_stencil_op(builder->create_info.gfx->pDepthStencilState->back.failOp);
669bf215546Sopenharmony_ci   pipeline->zs.s_back.pass_op =
670bf215546Sopenharmony_ci      translate_stencil_op(builder->create_info.gfx->pDepthStencilState->back.passOp);
671bf215546Sopenharmony_ci   pipeline->zs.s_back.z_fail_op =
672bf215546Sopenharmony_ci      translate_stencil_op(builder->create_info.gfx->pDepthStencilState->back.depthFailOp);
673bf215546Sopenharmony_ci   pipeline->zs.s_back.compare_func =
674bf215546Sopenharmony_ci      panvk_per_arch(translate_compare_func)(builder->create_info.gfx->pDepthStencilState->back.compareOp);
675bf215546Sopenharmony_ci   pipeline->zs.s_back.compare_mask =
676bf215546Sopenharmony_ci      builder->create_info.gfx->pDepthStencilState->back.compareMask;
677bf215546Sopenharmony_ci   pipeline->zs.s_back.write_mask =
678bf215546Sopenharmony_ci      builder->create_info.gfx->pDepthStencilState->back.writeMask;
679bf215546Sopenharmony_ci   pipeline->zs.s_back.ref =
680bf215546Sopenharmony_ci      builder->create_info.gfx->pDepthStencilState->back.reference;
681bf215546Sopenharmony_ci}
682bf215546Sopenharmony_ci
683bf215546Sopenharmony_cistatic void
684bf215546Sopenharmony_cipanvk_pipeline_builder_parse_rast(struct panvk_pipeline_builder *builder,
685bf215546Sopenharmony_ci                                  struct panvk_pipeline *pipeline)
686bf215546Sopenharmony_ci{
687bf215546Sopenharmony_ci   pipeline->rast.clamp_depth = builder->create_info.gfx->pRasterizationState->depthClampEnable;
688bf215546Sopenharmony_ci   pipeline->rast.depth_bias.enable = builder->create_info.gfx->pRasterizationState->depthBiasEnable;
689bf215546Sopenharmony_ci   pipeline->rast.depth_bias.constant_factor =
690bf215546Sopenharmony_ci      builder->create_info.gfx->pRasterizationState->depthBiasConstantFactor;
691bf215546Sopenharmony_ci   pipeline->rast.depth_bias.clamp = builder->create_info.gfx->pRasterizationState->depthBiasClamp;
692bf215546Sopenharmony_ci   pipeline->rast.depth_bias.slope_factor = builder->create_info.gfx->pRasterizationState->depthBiasSlopeFactor;
693bf215546Sopenharmony_ci   pipeline->rast.front_ccw = builder->create_info.gfx->pRasterizationState->frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE;
694bf215546Sopenharmony_ci   pipeline->rast.cull_front_face = builder->create_info.gfx->pRasterizationState->cullMode & VK_CULL_MODE_FRONT_BIT;
695bf215546Sopenharmony_ci   pipeline->rast.cull_back_face = builder->create_info.gfx->pRasterizationState->cullMode & VK_CULL_MODE_BACK_BIT;
696bf215546Sopenharmony_ci   pipeline->rast.line_width = builder->create_info.gfx->pRasterizationState->lineWidth;
697bf215546Sopenharmony_ci   pipeline->rast.enable = !builder->create_info.gfx->pRasterizationState->rasterizerDiscardEnable;
698bf215546Sopenharmony_ci}
699bf215546Sopenharmony_ci
700bf215546Sopenharmony_cistatic bool
701bf215546Sopenharmony_cipanvk_fs_required(struct panvk_pipeline *pipeline)
702bf215546Sopenharmony_ci{
703bf215546Sopenharmony_ci   const struct pan_shader_info *info = &pipeline->fs.info;
704bf215546Sopenharmony_ci
705bf215546Sopenharmony_ci   /* If we generally have side effects */
706bf215546Sopenharmony_ci   if (info->fs.sidefx)
707bf215546Sopenharmony_ci      return true;
708bf215546Sopenharmony_ci
709bf215546Sopenharmony_ci    /* If colour is written we need to execute */
710bf215546Sopenharmony_ci    const struct pan_blend_state *blend = &pipeline->blend.state;
711bf215546Sopenharmony_ci    for (unsigned i = 0; i < blend->rt_count; ++i) {
712bf215546Sopenharmony_ci       if (blend->rts[i].equation.color_mask)
713bf215546Sopenharmony_ci          return true;
714bf215546Sopenharmony_ci    }
715bf215546Sopenharmony_ci
716bf215546Sopenharmony_ci    /* If depth is written and not implied we need to execute.
717bf215546Sopenharmony_ci     * TODO: Predicate on Z/S writes being enabled */
718bf215546Sopenharmony_ci    return (info->fs.writes_depth || info->fs.writes_stencil);
719bf215546Sopenharmony_ci}
720bf215546Sopenharmony_ci
721bf215546Sopenharmony_ci#define PANVK_DYNAMIC_FS_RSD_MASK \
722bf215546Sopenharmony_ci        ((1 << VK_DYNAMIC_STATE_DEPTH_BIAS) | \
723bf215546Sopenharmony_ci         (1 << VK_DYNAMIC_STATE_BLEND_CONSTANTS) | \
724bf215546Sopenharmony_ci         (1 << VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) | \
725bf215546Sopenharmony_ci         (1 << VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) | \
726bf215546Sopenharmony_ci         (1 << VK_DYNAMIC_STATE_STENCIL_REFERENCE))
727bf215546Sopenharmony_ci
728bf215546Sopenharmony_cistatic void
729bf215546Sopenharmony_cipanvk_pipeline_builder_init_fs_state(struct panvk_pipeline_builder *builder,
730bf215546Sopenharmony_ci                                     struct panvk_pipeline *pipeline)
731bf215546Sopenharmony_ci{
732bf215546Sopenharmony_ci   if (!builder->shaders[MESA_SHADER_FRAGMENT])
733bf215546Sopenharmony_ci      return;
734bf215546Sopenharmony_ci
735bf215546Sopenharmony_ci   pipeline->fs.dynamic_rsd =
736bf215546Sopenharmony_ci      pipeline->dynamic_state_mask & PANVK_DYNAMIC_FS_RSD_MASK;
737bf215546Sopenharmony_ci   pipeline->fs.address = pipeline->binary_bo->ptr.gpu +
738bf215546Sopenharmony_ci                          builder->stages[MESA_SHADER_FRAGMENT].shader_offset;
739bf215546Sopenharmony_ci   pipeline->fs.info = builder->shaders[MESA_SHADER_FRAGMENT]->info;
740bf215546Sopenharmony_ci   pipeline->fs.rt_mask = builder->active_color_attachments;
741bf215546Sopenharmony_ci   pipeline->fs.required = panvk_fs_required(pipeline);
742bf215546Sopenharmony_ci}
743bf215546Sopenharmony_ci
744bf215546Sopenharmony_cistatic void
745bf215546Sopenharmony_cipanvk_pipeline_update_varying_slot(struct panvk_varyings_info *varyings,
746bf215546Sopenharmony_ci                                   gl_shader_stage stage,
747bf215546Sopenharmony_ci                                   const struct pan_shader_varying *varying,
748bf215546Sopenharmony_ci                                   bool input)
749bf215546Sopenharmony_ci{
750bf215546Sopenharmony_ci   gl_varying_slot loc = varying->location;
751bf215546Sopenharmony_ci   enum panvk_varying_buf_id buf_id = panvk_varying_buf_id(loc);
752bf215546Sopenharmony_ci
753bf215546Sopenharmony_ci   varyings->stage[stage].loc[varyings->stage[stage].count++] = loc;
754bf215546Sopenharmony_ci
755bf215546Sopenharmony_ci   assert(loc < ARRAY_SIZE(varyings->varying));
756bf215546Sopenharmony_ci
757bf215546Sopenharmony_ci   enum pipe_format new_fmt = varying->format;
758bf215546Sopenharmony_ci   enum pipe_format old_fmt = varyings->varying[loc].format;
759bf215546Sopenharmony_ci
760bf215546Sopenharmony_ci   BITSET_SET(varyings->active, loc);
761bf215546Sopenharmony_ci
762bf215546Sopenharmony_ci   /* We expect inputs to either be set by a previous stage or be built
763bf215546Sopenharmony_ci    * in, skip the entry if that's not the case, we'll emit a const
764bf215546Sopenharmony_ci    * varying returning zero for those entries.
765bf215546Sopenharmony_ci    */
766bf215546Sopenharmony_ci   if (input && old_fmt == PIPE_FORMAT_NONE)
767bf215546Sopenharmony_ci      return;
768bf215546Sopenharmony_ci
769bf215546Sopenharmony_ci   unsigned new_size = util_format_get_blocksize(new_fmt);
770bf215546Sopenharmony_ci   unsigned old_size = util_format_get_blocksize(old_fmt);
771bf215546Sopenharmony_ci
772bf215546Sopenharmony_ci   if (old_size < new_size)
773bf215546Sopenharmony_ci      varyings->varying[loc].format = new_fmt;
774bf215546Sopenharmony_ci
775bf215546Sopenharmony_ci   varyings->buf_mask |= 1 << buf_id;
776bf215546Sopenharmony_ci}
777bf215546Sopenharmony_ci
778bf215546Sopenharmony_cistatic void
779bf215546Sopenharmony_cipanvk_pipeline_builder_collect_varyings(struct panvk_pipeline_builder *builder,
780bf215546Sopenharmony_ci                                        struct panvk_pipeline *pipeline)
781bf215546Sopenharmony_ci{
782bf215546Sopenharmony_ci   for (uint32_t s = 0; s < MESA_SHADER_STAGES; s++) {
783bf215546Sopenharmony_ci      if (!builder->shaders[s])
784bf215546Sopenharmony_ci         continue;
785bf215546Sopenharmony_ci
786bf215546Sopenharmony_ci      const struct pan_shader_info *info = &builder->shaders[s]->info;
787bf215546Sopenharmony_ci
788bf215546Sopenharmony_ci      for (unsigned i = 0; i < info->varyings.input_count; i++) {
789bf215546Sopenharmony_ci         panvk_pipeline_update_varying_slot(&pipeline->varyings, s,
790bf215546Sopenharmony_ci                                            &info->varyings.input[i],
791bf215546Sopenharmony_ci                                            true);
792bf215546Sopenharmony_ci      }
793bf215546Sopenharmony_ci
794bf215546Sopenharmony_ci      for (unsigned i = 0; i < info->varyings.output_count; i++) {
795bf215546Sopenharmony_ci         panvk_pipeline_update_varying_slot(&pipeline->varyings, s,
796bf215546Sopenharmony_ci                                            &info->varyings.output[i],
797bf215546Sopenharmony_ci                                            false);
798bf215546Sopenharmony_ci      }
799bf215546Sopenharmony_ci   }
800bf215546Sopenharmony_ci
801bf215546Sopenharmony_ci   /* TODO: Xfb */
802bf215546Sopenharmony_ci   gl_varying_slot loc;
803bf215546Sopenharmony_ci   BITSET_FOREACH_SET(loc, pipeline->varyings.active, VARYING_SLOT_MAX) {
804bf215546Sopenharmony_ci      if (pipeline->varyings.varying[loc].format == PIPE_FORMAT_NONE)
805bf215546Sopenharmony_ci         continue;
806bf215546Sopenharmony_ci
807bf215546Sopenharmony_ci      enum panvk_varying_buf_id buf_id = panvk_varying_buf_id(loc);
808bf215546Sopenharmony_ci      unsigned buf_idx = panvk_varying_buf_index(&pipeline->varyings, buf_id);
809bf215546Sopenharmony_ci      unsigned varying_sz = panvk_varying_size(&pipeline->varyings, loc);
810bf215546Sopenharmony_ci
811bf215546Sopenharmony_ci      pipeline->varyings.varying[loc].buf = buf_idx;
812bf215546Sopenharmony_ci      pipeline->varyings.varying[loc].offset =
813bf215546Sopenharmony_ci         pipeline->varyings.buf[buf_idx].stride;
814bf215546Sopenharmony_ci      pipeline->varyings.buf[buf_idx].stride += varying_sz;
815bf215546Sopenharmony_ci   }
816bf215546Sopenharmony_ci}
817bf215546Sopenharmony_ci
818bf215546Sopenharmony_cistatic void
819bf215546Sopenharmony_cipanvk_pipeline_builder_parse_vertex_input(struct panvk_pipeline_builder *builder,
820bf215546Sopenharmony_ci                                          struct panvk_pipeline *pipeline)
821bf215546Sopenharmony_ci{
822bf215546Sopenharmony_ci   struct panvk_attribs_info *attribs = &pipeline->attribs;
823bf215546Sopenharmony_ci   const VkPipelineVertexInputStateCreateInfo *info =
824bf215546Sopenharmony_ci      builder->create_info.gfx->pVertexInputState;
825bf215546Sopenharmony_ci
826bf215546Sopenharmony_ci   const VkPipelineVertexInputDivisorStateCreateInfoEXT *div_info =
827bf215546Sopenharmony_ci      vk_find_struct_const(info->pNext,
828bf215546Sopenharmony_ci                           PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT);
829bf215546Sopenharmony_ci
830bf215546Sopenharmony_ci   for (unsigned i = 0; i < info->vertexBindingDescriptionCount; i++) {
831bf215546Sopenharmony_ci      const VkVertexInputBindingDescription *desc =
832bf215546Sopenharmony_ci         &info->pVertexBindingDescriptions[i];
833bf215546Sopenharmony_ci      attribs->buf_count = MAX2(desc->binding + 1, attribs->buf_count);
834bf215546Sopenharmony_ci      attribs->buf[desc->binding].stride = desc->stride;
835bf215546Sopenharmony_ci      attribs->buf[desc->binding].per_instance =
836bf215546Sopenharmony_ci         desc->inputRate == VK_VERTEX_INPUT_RATE_INSTANCE;
837bf215546Sopenharmony_ci      attribs->buf[desc->binding].instance_divisor = 1;
838bf215546Sopenharmony_ci      attribs->buf[desc->binding].special = false;
839bf215546Sopenharmony_ci   }
840bf215546Sopenharmony_ci
841bf215546Sopenharmony_ci   if (div_info) {
842bf215546Sopenharmony_ci      for (unsigned i = 0; i < div_info->vertexBindingDivisorCount; i++) {
843bf215546Sopenharmony_ci         const VkVertexInputBindingDivisorDescriptionEXT *div =
844bf215546Sopenharmony_ci            &div_info->pVertexBindingDivisors[i];
845bf215546Sopenharmony_ci         attribs->buf[div->binding].instance_divisor = div->divisor;
846bf215546Sopenharmony_ci      }
847bf215546Sopenharmony_ci   }
848bf215546Sopenharmony_ci
849bf215546Sopenharmony_ci   const struct pan_shader_info *vs =
850bf215546Sopenharmony_ci      &builder->shaders[MESA_SHADER_VERTEX]->info;
851bf215546Sopenharmony_ci
852bf215546Sopenharmony_ci   for (unsigned i = 0; i < info->vertexAttributeDescriptionCount; i++) {
853bf215546Sopenharmony_ci      const VkVertexInputAttributeDescription *desc =
854bf215546Sopenharmony_ci         &info->pVertexAttributeDescriptions[i];
855bf215546Sopenharmony_ci
856bf215546Sopenharmony_ci      unsigned attrib = desc->location + VERT_ATTRIB_GENERIC0;
857bf215546Sopenharmony_ci      unsigned slot = util_bitcount64(vs->attributes_read &
858bf215546Sopenharmony_ci                                      BITFIELD64_MASK(attrib));
859bf215546Sopenharmony_ci
860bf215546Sopenharmony_ci      attribs->attrib[slot].buf = desc->binding;
861bf215546Sopenharmony_ci      attribs->attrib[slot].format =
862bf215546Sopenharmony_ci         vk_format_to_pipe_format(desc->format);
863bf215546Sopenharmony_ci      attribs->attrib[slot].offset = desc->offset;
864bf215546Sopenharmony_ci   }
865bf215546Sopenharmony_ci
866bf215546Sopenharmony_ci   if (vs->attribute_count >= PAN_VERTEX_ID) {
867bf215546Sopenharmony_ci      attribs->buf[attribs->buf_count].special = true;
868bf215546Sopenharmony_ci      attribs->buf[attribs->buf_count].special_id = PAN_VERTEX_ID;
869bf215546Sopenharmony_ci      attribs->attrib[PAN_VERTEX_ID].buf = attribs->buf_count++;
870bf215546Sopenharmony_ci      attribs->attrib[PAN_VERTEX_ID].format = PIPE_FORMAT_R32_UINT;
871bf215546Sopenharmony_ci   }
872bf215546Sopenharmony_ci
873bf215546Sopenharmony_ci   if (vs->attribute_count >= PAN_INSTANCE_ID) {
874bf215546Sopenharmony_ci      attribs->buf[attribs->buf_count].special = true;
875bf215546Sopenharmony_ci      attribs->buf[attribs->buf_count].special_id = PAN_INSTANCE_ID;
876bf215546Sopenharmony_ci      attribs->attrib[PAN_INSTANCE_ID].buf = attribs->buf_count++;
877bf215546Sopenharmony_ci      attribs->attrib[PAN_INSTANCE_ID].format = PIPE_FORMAT_R32_UINT;
878bf215546Sopenharmony_ci   }
879bf215546Sopenharmony_ci
880bf215546Sopenharmony_ci   attribs->attrib_count = MAX2(attribs->attrib_count, vs->attribute_count);
881bf215546Sopenharmony_ci}
882bf215546Sopenharmony_ci
883bf215546Sopenharmony_cistatic VkResult
884bf215546Sopenharmony_cipanvk_pipeline_builder_build(struct panvk_pipeline_builder *builder,
885bf215546Sopenharmony_ci                             struct panvk_pipeline **pipeline)
886bf215546Sopenharmony_ci{
887bf215546Sopenharmony_ci   VkResult result = panvk_pipeline_builder_create_pipeline(builder, pipeline);
888bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
889bf215546Sopenharmony_ci      return result;
890bf215546Sopenharmony_ci
891bf215546Sopenharmony_ci   /* TODO: make those functions return a result and handle errors */
892bf215546Sopenharmony_ci   if (builder->create_info.gfx) {
893bf215546Sopenharmony_ci      panvk_pipeline_builder_parse_dynamic(builder, *pipeline);
894bf215546Sopenharmony_ci      panvk_pipeline_builder_parse_color_blend(builder, *pipeline);
895bf215546Sopenharmony_ci      panvk_pipeline_builder_compile_shaders(builder, *pipeline);
896bf215546Sopenharmony_ci      panvk_pipeline_builder_collect_varyings(builder, *pipeline);
897bf215546Sopenharmony_ci      panvk_pipeline_builder_parse_input_assembly(builder, *pipeline);
898bf215546Sopenharmony_ci      panvk_pipeline_builder_parse_multisample(builder, *pipeline);
899bf215546Sopenharmony_ci      panvk_pipeline_builder_parse_zs(builder, *pipeline);
900bf215546Sopenharmony_ci      panvk_pipeline_builder_parse_rast(builder, *pipeline);
901bf215546Sopenharmony_ci      panvk_pipeline_builder_parse_vertex_input(builder, *pipeline);
902bf215546Sopenharmony_ci      panvk_pipeline_builder_upload_shaders(builder, *pipeline);
903bf215546Sopenharmony_ci      panvk_pipeline_builder_init_fs_state(builder, *pipeline);
904bf215546Sopenharmony_ci      panvk_pipeline_builder_alloc_static_state_bo(builder, *pipeline);
905bf215546Sopenharmony_ci      panvk_pipeline_builder_init_shaders(builder, *pipeline);
906bf215546Sopenharmony_ci      panvk_pipeline_builder_parse_viewport(builder, *pipeline);
907bf215546Sopenharmony_ci   } else {
908bf215546Sopenharmony_ci      panvk_pipeline_builder_compile_shaders(builder, *pipeline);
909bf215546Sopenharmony_ci      panvk_pipeline_builder_upload_shaders(builder, *pipeline);
910bf215546Sopenharmony_ci      panvk_pipeline_builder_alloc_static_state_bo(builder, *pipeline);
911bf215546Sopenharmony_ci      panvk_pipeline_builder_init_shaders(builder, *pipeline);
912bf215546Sopenharmony_ci   }
913bf215546Sopenharmony_ci
914bf215546Sopenharmony_ci   return VK_SUCCESS;
915bf215546Sopenharmony_ci}
916bf215546Sopenharmony_ci
917bf215546Sopenharmony_cistatic void
918bf215546Sopenharmony_cipanvk_pipeline_builder_init_graphics(struct panvk_pipeline_builder *builder,
919bf215546Sopenharmony_ci                                     struct panvk_device *dev,
920bf215546Sopenharmony_ci                                     struct panvk_pipeline_cache *cache,
921bf215546Sopenharmony_ci                                     const VkGraphicsPipelineCreateInfo *create_info,
922bf215546Sopenharmony_ci                                     const VkAllocationCallbacks *alloc)
923bf215546Sopenharmony_ci{
924bf215546Sopenharmony_ci   VK_FROM_HANDLE(panvk_pipeline_layout, layout, create_info->layout);
925bf215546Sopenharmony_ci   assert(layout);
926bf215546Sopenharmony_ci   *builder = (struct panvk_pipeline_builder) {
927bf215546Sopenharmony_ci      .device = dev,
928bf215546Sopenharmony_ci      .cache = cache,
929bf215546Sopenharmony_ci      .layout = layout,
930bf215546Sopenharmony_ci      .create_info.gfx = create_info,
931bf215546Sopenharmony_ci      .alloc = alloc,
932bf215546Sopenharmony_ci   };
933bf215546Sopenharmony_ci
934bf215546Sopenharmony_ci   builder->rasterizer_discard =
935bf215546Sopenharmony_ci      create_info->pRasterizationState->rasterizerDiscardEnable;
936bf215546Sopenharmony_ci
937bf215546Sopenharmony_ci   if (builder->rasterizer_discard) {
938bf215546Sopenharmony_ci      builder->samples = VK_SAMPLE_COUNT_1_BIT;
939bf215546Sopenharmony_ci   } else {
940bf215546Sopenharmony_ci      builder->samples = create_info->pMultisampleState->rasterizationSamples;
941bf215546Sopenharmony_ci
942bf215546Sopenharmony_ci      const struct panvk_render_pass *pass = panvk_render_pass_from_handle(create_info->renderPass);
943bf215546Sopenharmony_ci      const struct panvk_subpass *subpass = &pass->subpasses[create_info->subpass];
944bf215546Sopenharmony_ci
945bf215546Sopenharmony_ci      builder->use_depth_stencil_attachment =
946bf215546Sopenharmony_ci         subpass->zs_attachment.idx != VK_ATTACHMENT_UNUSED;
947bf215546Sopenharmony_ci
948bf215546Sopenharmony_ci      assert(subpass->color_count <= create_info->pColorBlendState->attachmentCount);
949bf215546Sopenharmony_ci      builder->active_color_attachments = 0;
950bf215546Sopenharmony_ci      for (uint32_t i = 0; i < subpass->color_count; i++) {
951bf215546Sopenharmony_ci         uint32_t idx = subpass->color_attachments[i].idx;
952bf215546Sopenharmony_ci         if (idx == VK_ATTACHMENT_UNUSED)
953bf215546Sopenharmony_ci            continue;
954bf215546Sopenharmony_ci
955bf215546Sopenharmony_ci         builder->active_color_attachments |= 1 << i;
956bf215546Sopenharmony_ci         builder->color_attachment_formats[i] = pass->attachments[idx].format;
957bf215546Sopenharmony_ci      }
958bf215546Sopenharmony_ci   }
959bf215546Sopenharmony_ci}
960bf215546Sopenharmony_ci
961bf215546Sopenharmony_ciVkResult
962bf215546Sopenharmony_cipanvk_per_arch(CreateGraphicsPipelines)(VkDevice device,
963bf215546Sopenharmony_ci                                        VkPipelineCache pipelineCache,
964bf215546Sopenharmony_ci                                        uint32_t count,
965bf215546Sopenharmony_ci                                        const VkGraphicsPipelineCreateInfo *pCreateInfos,
966bf215546Sopenharmony_ci                                        const VkAllocationCallbacks *pAllocator,
967bf215546Sopenharmony_ci                                        VkPipeline *pPipelines)
968bf215546Sopenharmony_ci{
969bf215546Sopenharmony_ci   VK_FROM_HANDLE(panvk_device, dev, device);
970bf215546Sopenharmony_ci   VK_FROM_HANDLE(panvk_pipeline_cache, cache, pipelineCache);
971bf215546Sopenharmony_ci
972bf215546Sopenharmony_ci   for (uint32_t i = 0; i < count; i++) {
973bf215546Sopenharmony_ci      struct panvk_pipeline_builder builder;
974bf215546Sopenharmony_ci      panvk_pipeline_builder_init_graphics(&builder, dev, cache,
975bf215546Sopenharmony_ci                                           &pCreateInfos[i], pAllocator);
976bf215546Sopenharmony_ci
977bf215546Sopenharmony_ci      struct panvk_pipeline *pipeline;
978bf215546Sopenharmony_ci      VkResult result = panvk_pipeline_builder_build(&builder, &pipeline);
979bf215546Sopenharmony_ci      panvk_pipeline_builder_finish(&builder);
980bf215546Sopenharmony_ci
981bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
982bf215546Sopenharmony_ci         for (uint32_t j = 0; j < i; j++) {
983bf215546Sopenharmony_ci            panvk_DestroyPipeline(device, pPipelines[j], pAllocator);
984bf215546Sopenharmony_ci            pPipelines[j] = VK_NULL_HANDLE;
985bf215546Sopenharmony_ci         }
986bf215546Sopenharmony_ci
987bf215546Sopenharmony_ci         return result;
988bf215546Sopenharmony_ci      }
989bf215546Sopenharmony_ci
990bf215546Sopenharmony_ci      pPipelines[i] = panvk_pipeline_to_handle(pipeline);
991bf215546Sopenharmony_ci   }
992bf215546Sopenharmony_ci
993bf215546Sopenharmony_ci   return VK_SUCCESS;
994bf215546Sopenharmony_ci}
995bf215546Sopenharmony_ci
996bf215546Sopenharmony_cistatic void
997bf215546Sopenharmony_cipanvk_pipeline_builder_init_compute(struct panvk_pipeline_builder *builder,
998bf215546Sopenharmony_ci                                    struct panvk_device *dev,
999bf215546Sopenharmony_ci                                    struct panvk_pipeline_cache *cache,
1000bf215546Sopenharmony_ci                                    const VkComputePipelineCreateInfo *create_info,
1001bf215546Sopenharmony_ci                                    const VkAllocationCallbacks *alloc)
1002bf215546Sopenharmony_ci{
1003bf215546Sopenharmony_ci   VK_FROM_HANDLE(panvk_pipeline_layout, layout, create_info->layout);
1004bf215546Sopenharmony_ci   assert(layout);
1005bf215546Sopenharmony_ci   *builder = (struct panvk_pipeline_builder) {
1006bf215546Sopenharmony_ci      .device = dev,
1007bf215546Sopenharmony_ci      .cache = cache,
1008bf215546Sopenharmony_ci      .layout = layout,
1009bf215546Sopenharmony_ci      .create_info.compute = create_info,
1010bf215546Sopenharmony_ci      .alloc = alloc,
1011bf215546Sopenharmony_ci   };
1012bf215546Sopenharmony_ci}
1013bf215546Sopenharmony_ci
1014bf215546Sopenharmony_ciVkResult
1015bf215546Sopenharmony_cipanvk_per_arch(CreateComputePipelines)(VkDevice device,
1016bf215546Sopenharmony_ci                                       VkPipelineCache pipelineCache,
1017bf215546Sopenharmony_ci                                       uint32_t count,
1018bf215546Sopenharmony_ci                                       const VkComputePipelineCreateInfo *pCreateInfos,
1019bf215546Sopenharmony_ci                                       const VkAllocationCallbacks *pAllocator,
1020bf215546Sopenharmony_ci                                       VkPipeline *pPipelines)
1021bf215546Sopenharmony_ci{
1022bf215546Sopenharmony_ci   VK_FROM_HANDLE(panvk_device, dev, device);
1023bf215546Sopenharmony_ci   VK_FROM_HANDLE(panvk_pipeline_cache, cache, pipelineCache);
1024bf215546Sopenharmony_ci
1025bf215546Sopenharmony_ci   for (uint32_t i = 0; i < count; i++) {
1026bf215546Sopenharmony_ci      struct panvk_pipeline_builder builder;
1027bf215546Sopenharmony_ci      panvk_pipeline_builder_init_compute(&builder, dev, cache,
1028bf215546Sopenharmony_ci                                          &pCreateInfos[i], pAllocator);
1029bf215546Sopenharmony_ci
1030bf215546Sopenharmony_ci      struct panvk_pipeline *pipeline;
1031bf215546Sopenharmony_ci      VkResult result = panvk_pipeline_builder_build(&builder, &pipeline);
1032bf215546Sopenharmony_ci      panvk_pipeline_builder_finish(&builder);
1033bf215546Sopenharmony_ci
1034bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
1035bf215546Sopenharmony_ci         for (uint32_t j = 0; j < i; j++) {
1036bf215546Sopenharmony_ci            panvk_DestroyPipeline(device, pPipelines[j], pAllocator);
1037bf215546Sopenharmony_ci            pPipelines[j] = VK_NULL_HANDLE;
1038bf215546Sopenharmony_ci         }
1039bf215546Sopenharmony_ci
1040bf215546Sopenharmony_ci         return result;
1041bf215546Sopenharmony_ci      }
1042bf215546Sopenharmony_ci
1043bf215546Sopenharmony_ci      pPipelines[i] = panvk_pipeline_to_handle(pipeline);
1044bf215546Sopenharmony_ci   }
1045bf215546Sopenharmony_ci
1046bf215546Sopenharmony_ci   return VK_SUCCESS;
1047bf215546Sopenharmony_ci}
1048