1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2019 Red Hat.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "lvp_private.h"
25bf215546Sopenharmony_ci#include "vk_pipeline.h"
26bf215546Sopenharmony_ci#include "vk_render_pass.h"
27bf215546Sopenharmony_ci#include "vk_util.h"
28bf215546Sopenharmony_ci#include "glsl_types.h"
29bf215546Sopenharmony_ci#include "util/os_time.h"
30bf215546Sopenharmony_ci#include "spirv/nir_spirv.h"
31bf215546Sopenharmony_ci#include "nir/nir_builder.h"
32bf215546Sopenharmony_ci#include "lvp_lower_vulkan_resource.h"
33bf215546Sopenharmony_ci#include "pipe/p_state.h"
34bf215546Sopenharmony_ci#include "pipe/p_context.h"
35bf215546Sopenharmony_ci#include "tgsi/tgsi_from_mesa.h"
36bf215546Sopenharmony_ci#include "nir/nir_xfb_info.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci#define SPIR_V_MAGIC_NUMBER 0x07230203
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci#define LVP_PIPELINE_DUP(dst, src, type, count) do {             \
41bf215546Sopenharmony_ci      type *temp = ralloc_array(mem_ctx, type, count);           \
42bf215546Sopenharmony_ci      if (!temp) return VK_ERROR_OUT_OF_HOST_MEMORY;             \
43bf215546Sopenharmony_ci      memcpy(temp, (src), sizeof(type) * count);                 \
44bf215546Sopenharmony_ci      dst = temp;                                                \
45bf215546Sopenharmony_ci   } while(0)
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_civoid
48bf215546Sopenharmony_cilvp_pipeline_destroy(struct lvp_device *device, struct lvp_pipeline *pipeline)
49bf215546Sopenharmony_ci{
50bf215546Sopenharmony_ci   if (pipeline->shader_cso[PIPE_SHADER_VERTEX])
51bf215546Sopenharmony_ci      device->queue.ctx->delete_vs_state(device->queue.ctx, pipeline->shader_cso[PIPE_SHADER_VERTEX]);
52bf215546Sopenharmony_ci   if (pipeline->shader_cso[PIPE_SHADER_FRAGMENT])
53bf215546Sopenharmony_ci      device->queue.ctx->delete_fs_state(device->queue.ctx, pipeline->shader_cso[PIPE_SHADER_FRAGMENT]);
54bf215546Sopenharmony_ci   if (pipeline->shader_cso[PIPE_SHADER_GEOMETRY])
55bf215546Sopenharmony_ci      device->queue.ctx->delete_gs_state(device->queue.ctx, pipeline->shader_cso[PIPE_SHADER_GEOMETRY]);
56bf215546Sopenharmony_ci   if (pipeline->shader_cso[PIPE_SHADER_TESS_CTRL])
57bf215546Sopenharmony_ci      device->queue.ctx->delete_tcs_state(device->queue.ctx, pipeline->shader_cso[PIPE_SHADER_TESS_CTRL]);
58bf215546Sopenharmony_ci   if (pipeline->shader_cso[PIPE_SHADER_TESS_EVAL])
59bf215546Sopenharmony_ci      device->queue.ctx->delete_tes_state(device->queue.ctx, pipeline->shader_cso[PIPE_SHADER_TESS_EVAL]);
60bf215546Sopenharmony_ci   if (pipeline->shader_cso[PIPE_SHADER_COMPUTE])
61bf215546Sopenharmony_ci      device->queue.ctx->delete_compute_state(device->queue.ctx, pipeline->shader_cso[PIPE_SHADER_COMPUTE]);
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++)
64bf215546Sopenharmony_ci      ralloc_free(pipeline->pipeline_nir[i]);
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   if (pipeline->layout)
67bf215546Sopenharmony_ci      vk_pipeline_layout_unref(&device->vk, &pipeline->layout->vk);
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci   ralloc_free(pipeline->mem_ctx);
70bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, pipeline->state_data);
71bf215546Sopenharmony_ci   vk_object_base_finish(&pipeline->base);
72bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, pipeline);
73bf215546Sopenharmony_ci}
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ciVKAPI_ATTR void VKAPI_CALL lvp_DestroyPipeline(
76bf215546Sopenharmony_ci   VkDevice                                    _device,
77bf215546Sopenharmony_ci   VkPipeline                                  _pipeline,
78bf215546Sopenharmony_ci   const VkAllocationCallbacks*                pAllocator)
79bf215546Sopenharmony_ci{
80bf215546Sopenharmony_ci   LVP_FROM_HANDLE(lvp_device, device, _device);
81bf215546Sopenharmony_ci   LVP_FROM_HANDLE(lvp_pipeline, pipeline, _pipeline);
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci   if (!_pipeline)
84bf215546Sopenharmony_ci      return;
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci   simple_mtx_lock(&device->queue.pipeline_lock);
87bf215546Sopenharmony_ci   util_dynarray_append(&device->queue.pipeline_destroys, struct lvp_pipeline*, pipeline);
88bf215546Sopenharmony_ci   simple_mtx_unlock(&device->queue.pipeline_lock);
89bf215546Sopenharmony_ci}
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_cistatic inline unsigned
92bf215546Sopenharmony_cist_shader_stage_to_ptarget(gl_shader_stage stage)
93bf215546Sopenharmony_ci{
94bf215546Sopenharmony_ci   switch (stage) {
95bf215546Sopenharmony_ci   case MESA_SHADER_VERTEX:
96bf215546Sopenharmony_ci      return PIPE_SHADER_VERTEX;
97bf215546Sopenharmony_ci   case MESA_SHADER_FRAGMENT:
98bf215546Sopenharmony_ci      return PIPE_SHADER_FRAGMENT;
99bf215546Sopenharmony_ci   case MESA_SHADER_GEOMETRY:
100bf215546Sopenharmony_ci      return PIPE_SHADER_GEOMETRY;
101bf215546Sopenharmony_ci   case MESA_SHADER_TESS_CTRL:
102bf215546Sopenharmony_ci      return PIPE_SHADER_TESS_CTRL;
103bf215546Sopenharmony_ci   case MESA_SHADER_TESS_EVAL:
104bf215546Sopenharmony_ci      return PIPE_SHADER_TESS_EVAL;
105bf215546Sopenharmony_ci   case MESA_SHADER_COMPUTE:
106bf215546Sopenharmony_ci      return PIPE_SHADER_COMPUTE;
107bf215546Sopenharmony_ci   default:
108bf215546Sopenharmony_ci      break;
109bf215546Sopenharmony_ci   }
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci   assert(!"should not be reached");
112bf215546Sopenharmony_ci   return PIPE_SHADER_VERTEX;
113bf215546Sopenharmony_ci}
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_cistatic void
116bf215546Sopenharmony_cishared_var_info(const struct glsl_type *type, unsigned *size, unsigned *align)
117bf215546Sopenharmony_ci{
118bf215546Sopenharmony_ci   assert(glsl_type_is_vector_or_scalar(type));
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   uint32_t comp_size = glsl_type_is_boolean(type)
121bf215546Sopenharmony_ci      ? 4 : glsl_get_bit_size(type) / 8;
122bf215546Sopenharmony_ci   unsigned length = glsl_get_vector_elements(type);
123bf215546Sopenharmony_ci   *size = comp_size * length,
124bf215546Sopenharmony_ci      *align = comp_size;
125bf215546Sopenharmony_ci}
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_cistatic void
128bf215546Sopenharmony_ciset_image_access(struct lvp_pipeline *pipeline, nir_shader *nir,
129bf215546Sopenharmony_ci                   nir_intrinsic_instr *instr,
130bf215546Sopenharmony_ci                   bool reads, bool writes)
131bf215546Sopenharmony_ci{
132bf215546Sopenharmony_ci   nir_variable *var = nir_intrinsic_get_var(instr, 0);
133bf215546Sopenharmony_ci   /* calculate the variable's offset in the layout */
134bf215546Sopenharmony_ci   uint64_t value = 0;
135bf215546Sopenharmony_ci   const struct lvp_descriptor_set_binding_layout *binding =
136bf215546Sopenharmony_ci      get_binding_layout(pipeline->layout, var->data.descriptor_set, var->data.binding);
137bf215546Sopenharmony_ci   for (unsigned s = 0; s < var->data.descriptor_set; s++) {
138bf215546Sopenharmony_ci     if (pipeline->layout->vk.set_layouts[s])
139bf215546Sopenharmony_ci        value += get_set_layout(pipeline->layout, s)->stage[nir->info.stage].image_count;
140bf215546Sopenharmony_ci   }
141bf215546Sopenharmony_ci   value += binding->stage[nir->info.stage].image_index;
142bf215546Sopenharmony_ci   const unsigned size = glsl_type_is_array(var->type) ? glsl_get_aoa_size(var->type) : 1;
143bf215546Sopenharmony_ci   uint64_t mask = BITFIELD64_MASK(MAX2(size, 1)) << value;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   if (reads)
146bf215546Sopenharmony_ci      pipeline->access[nir->info.stage].images_read |= mask;
147bf215546Sopenharmony_ci   if (writes)
148bf215546Sopenharmony_ci      pipeline->access[nir->info.stage].images_written |= mask;
149bf215546Sopenharmony_ci}
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_cistatic void
152bf215546Sopenharmony_ciset_buffer_access(struct lvp_pipeline *pipeline, nir_shader *nir,
153bf215546Sopenharmony_ci                    nir_intrinsic_instr *instr)
154bf215546Sopenharmony_ci{
155bf215546Sopenharmony_ci   nir_variable *var = nir_intrinsic_get_var(instr, 0);
156bf215546Sopenharmony_ci   if (!var) {
157bf215546Sopenharmony_ci      nir_deref_instr *deref = nir_instr_as_deref(instr->src[0].ssa->parent_instr);
158bf215546Sopenharmony_ci      if (deref->modes != nir_var_mem_ssbo)
159bf215546Sopenharmony_ci         return;
160bf215546Sopenharmony_ci      nir_binding b = nir_chase_binding(instr->src[0]);
161bf215546Sopenharmony_ci      var = nir_get_binding_variable(nir, b);
162bf215546Sopenharmony_ci      if (!var)
163bf215546Sopenharmony_ci         return;
164bf215546Sopenharmony_ci   }
165bf215546Sopenharmony_ci   if (var->data.mode != nir_var_mem_ssbo)
166bf215546Sopenharmony_ci      return;
167bf215546Sopenharmony_ci   /* calculate the variable's offset in the layout */
168bf215546Sopenharmony_ci   uint64_t value = 0;
169bf215546Sopenharmony_ci   const struct lvp_descriptor_set_binding_layout *binding =
170bf215546Sopenharmony_ci      get_binding_layout(pipeline->layout, var->data.descriptor_set, var->data.binding);
171bf215546Sopenharmony_ci   for (unsigned s = 0; s < var->data.descriptor_set; s++) {
172bf215546Sopenharmony_ci     if (pipeline->layout->vk.set_layouts[s])
173bf215546Sopenharmony_ci        value += get_set_layout(pipeline->layout, s)->stage[nir->info.stage].shader_buffer_count;
174bf215546Sopenharmony_ci   }
175bf215546Sopenharmony_ci   value += binding->stage[nir->info.stage].shader_buffer_index;
176bf215546Sopenharmony_ci   /* Structs have been lowered already, so get_aoa_size is sufficient. */
177bf215546Sopenharmony_ci   const unsigned size = glsl_type_is_array(var->type) ? glsl_get_aoa_size(var->type) : 1;
178bf215546Sopenharmony_ci   uint64_t mask = BITFIELD64_MASK(MAX2(size, 1)) << value;
179bf215546Sopenharmony_ci   pipeline->access[nir->info.stage].buffers_written |= mask;
180bf215546Sopenharmony_ci}
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_cistatic void
183bf215546Sopenharmony_ciscan_intrinsic(struct lvp_pipeline *pipeline, nir_shader *nir, nir_intrinsic_instr *instr)
184bf215546Sopenharmony_ci{
185bf215546Sopenharmony_ci   switch (instr->intrinsic) {
186bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_sparse_load:
187bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_load:
188bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_size:
189bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_samples:
190bf215546Sopenharmony_ci      set_image_access(pipeline, nir, instr, true, false);
191bf215546Sopenharmony_ci      break;
192bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_store:
193bf215546Sopenharmony_ci      set_image_access(pipeline, nir, instr, false, true);
194bf215546Sopenharmony_ci      break;
195bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_add:
196bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_imin:
197bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_umin:
198bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_imax:
199bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_umax:
200bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_and:
201bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_or:
202bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_xor:
203bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_exchange:
204bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_comp_swap:
205bf215546Sopenharmony_ci   case nir_intrinsic_image_deref_atomic_fadd:
206bf215546Sopenharmony_ci      set_image_access(pipeline, nir, instr, true, true);
207bf215546Sopenharmony_ci      break;
208bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_add:
209bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_and:
210bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_comp_swap:
211bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_exchange:
212bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_fadd:
213bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_fcomp_swap:
214bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_fmax:
215bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_fmin:
216bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_imax:
217bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_imin:
218bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_or:
219bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_umax:
220bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_umin:
221bf215546Sopenharmony_ci   case nir_intrinsic_deref_atomic_xor:
222bf215546Sopenharmony_ci   case nir_intrinsic_store_deref:
223bf215546Sopenharmony_ci      set_buffer_access(pipeline, nir, instr);
224bf215546Sopenharmony_ci      break;
225bf215546Sopenharmony_ci   default: break;
226bf215546Sopenharmony_ci   }
227bf215546Sopenharmony_ci}
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_cistatic void
230bf215546Sopenharmony_ciscan_pipeline_info(struct lvp_pipeline *pipeline, nir_shader *nir)
231bf215546Sopenharmony_ci{
232bf215546Sopenharmony_ci   nir_foreach_function(function, nir) {
233bf215546Sopenharmony_ci      if (function->impl)
234bf215546Sopenharmony_ci         nir_foreach_block(block, function->impl) {
235bf215546Sopenharmony_ci            nir_foreach_instr(instr, block) {
236bf215546Sopenharmony_ci               if (instr->type == nir_instr_type_intrinsic)
237bf215546Sopenharmony_ci                  scan_intrinsic(pipeline, nir, nir_instr_as_intrinsic(instr));
238bf215546Sopenharmony_ci            }
239bf215546Sopenharmony_ci         }
240bf215546Sopenharmony_ci   }
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_ci}
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_cistatic bool
245bf215546Sopenharmony_ciremove_scoped_barriers_impl(nir_builder *b, nir_instr *instr, void *data)
246bf215546Sopenharmony_ci{
247bf215546Sopenharmony_ci   if (instr->type != nir_instr_type_intrinsic)
248bf215546Sopenharmony_ci      return false;
249bf215546Sopenharmony_ci   nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
250bf215546Sopenharmony_ci   if (intr->intrinsic != nir_intrinsic_scoped_barrier)
251bf215546Sopenharmony_ci      return false;
252bf215546Sopenharmony_ci   if (data) {
253bf215546Sopenharmony_ci      if (nir_intrinsic_memory_scope(intr) == NIR_SCOPE_WORKGROUP ||
254bf215546Sopenharmony_ci          nir_intrinsic_memory_scope(intr) == NIR_SCOPE_DEVICE)
255bf215546Sopenharmony_ci         return false;
256bf215546Sopenharmony_ci   }
257bf215546Sopenharmony_ci   nir_instr_remove(instr);
258bf215546Sopenharmony_ci   return true;
259bf215546Sopenharmony_ci}
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_cistatic bool
262bf215546Sopenharmony_ciremove_scoped_barriers(nir_shader *nir, bool is_compute)
263bf215546Sopenharmony_ci{
264bf215546Sopenharmony_ci   return nir_shader_instructions_pass(nir, remove_scoped_barriers_impl, nir_metadata_dominance, (void*)is_compute);
265bf215546Sopenharmony_ci}
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_cistatic bool
268bf215546Sopenharmony_cilower_demote_impl(nir_builder *b, nir_instr *instr, void *data)
269bf215546Sopenharmony_ci{
270bf215546Sopenharmony_ci   if (instr->type != nir_instr_type_intrinsic)
271bf215546Sopenharmony_ci      return false;
272bf215546Sopenharmony_ci   nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
273bf215546Sopenharmony_ci   if (intr->intrinsic == nir_intrinsic_demote || intr->intrinsic == nir_intrinsic_terminate) {
274bf215546Sopenharmony_ci      intr->intrinsic = nir_intrinsic_discard;
275bf215546Sopenharmony_ci      return true;
276bf215546Sopenharmony_ci   }
277bf215546Sopenharmony_ci   if (intr->intrinsic == nir_intrinsic_demote_if || intr->intrinsic == nir_intrinsic_terminate_if) {
278bf215546Sopenharmony_ci      intr->intrinsic = nir_intrinsic_discard_if;
279bf215546Sopenharmony_ci      return true;
280bf215546Sopenharmony_ci   }
281bf215546Sopenharmony_ci   return false;
282bf215546Sopenharmony_ci}
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_cistatic bool
285bf215546Sopenharmony_cilower_demote(nir_shader *nir)
286bf215546Sopenharmony_ci{
287bf215546Sopenharmony_ci   return nir_shader_instructions_pass(nir, lower_demote_impl, nir_metadata_dominance, NULL);
288bf215546Sopenharmony_ci}
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_cistatic bool
291bf215546Sopenharmony_cifind_tex(const nir_instr *instr, const void *data_cb)
292bf215546Sopenharmony_ci{
293bf215546Sopenharmony_ci   if (instr->type == nir_instr_type_tex)
294bf215546Sopenharmony_ci      return true;
295bf215546Sopenharmony_ci   return false;
296bf215546Sopenharmony_ci}
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_cistatic nir_ssa_def *
299bf215546Sopenharmony_cifixup_tex_instr(struct nir_builder *b, nir_instr *instr, void *data_cb)
300bf215546Sopenharmony_ci{
301bf215546Sopenharmony_ci   nir_tex_instr *tex_instr = nir_instr_as_tex(instr);
302bf215546Sopenharmony_ci   unsigned offset = 0;
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   int idx = nir_tex_instr_src_index(tex_instr, nir_tex_src_texture_offset);
305bf215546Sopenharmony_ci   if (idx == -1)
306bf215546Sopenharmony_ci      return NULL;
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   if (!nir_src_is_const(tex_instr->src[idx].src))
309bf215546Sopenharmony_ci      return NULL;
310bf215546Sopenharmony_ci   offset = nir_src_comp_as_uint(tex_instr->src[idx].src, 0);
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci   nir_tex_instr_remove_src(tex_instr, idx);
313bf215546Sopenharmony_ci   tex_instr->texture_index += offset;
314bf215546Sopenharmony_ci   return NIR_LOWER_INSTR_PROGRESS;
315bf215546Sopenharmony_ci}
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_cistatic bool
318bf215546Sopenharmony_cilvp_nir_fixup_indirect_tex(nir_shader *shader)
319bf215546Sopenharmony_ci{
320bf215546Sopenharmony_ci   return nir_shader_lower_instructions(shader, find_tex, fixup_tex_instr, NULL);
321bf215546Sopenharmony_ci}
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_cistatic void
324bf215546Sopenharmony_cioptimize(nir_shader *nir)
325bf215546Sopenharmony_ci{
326bf215546Sopenharmony_ci   bool progress = false;
327bf215546Sopenharmony_ci   do {
328bf215546Sopenharmony_ci      progress = false;
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_lower_flrp, 32|64, true);
331bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_split_array_vars, nir_var_function_temp);
332bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_shrink_vec_array_vars, nir_var_function_temp);
333bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_deref);
334bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_lower_vars_to_ssa);
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_copy_prop_vars);
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_copy_prop);
339bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_dce);
340bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_peephole_select, 8, true, true);
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_algebraic);
343bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_constant_folding);
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_remove_phis);
346bf215546Sopenharmony_ci      bool trivial_continues = false;
347bf215546Sopenharmony_ci      NIR_PASS(trivial_continues, nir, nir_opt_trivial_continues);
348bf215546Sopenharmony_ci      progress |= trivial_continues;
349bf215546Sopenharmony_ci      if (trivial_continues) {
350bf215546Sopenharmony_ci         /* If nir_opt_trivial_continues makes progress, then we need to clean
351bf215546Sopenharmony_ci          * things up if we want any hope of nir_opt_if or nir_opt_loop_unroll
352bf215546Sopenharmony_ci          * to make progress.
353bf215546Sopenharmony_ci          */
354bf215546Sopenharmony_ci         NIR_PASS(progress, nir, nir_copy_prop);
355bf215546Sopenharmony_ci         NIR_PASS(progress, nir, nir_opt_dce);
356bf215546Sopenharmony_ci         NIR_PASS(progress, nir, nir_opt_remove_phis);
357bf215546Sopenharmony_ci      }
358bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_if, nir_opt_if_aggressive_last_continue | nir_opt_if_optimize_phi_true_false);
359bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_dead_cf);
360bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_conditional_discard);
361bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_remove_phis);
362bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_cse);
363bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_undef);
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_deref);
366bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_lower_alu_to_scalar, NULL, NULL);
367bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_loop_unroll);
368bf215546Sopenharmony_ci      NIR_PASS(progress, nir, lvp_nir_fixup_indirect_tex);
369bf215546Sopenharmony_ci   } while (progress);
370bf215546Sopenharmony_ci}
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_civoid
373bf215546Sopenharmony_cilvp_shader_optimize(nir_shader *nir)
374bf215546Sopenharmony_ci{
375bf215546Sopenharmony_ci   optimize(nir);
376bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_var_copies);
377bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp, NULL);
378bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_opt_dce);
379bf215546Sopenharmony_ci   nir_sweep(nir);
380bf215546Sopenharmony_ci}
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_cistatic VkResult
383bf215546Sopenharmony_cilvp_shader_compile_to_ir(struct lvp_pipeline *pipeline,
384bf215546Sopenharmony_ci                         const VkPipelineShaderStageCreateInfo *sinfo)
385bf215546Sopenharmony_ci{
386bf215546Sopenharmony_ci   struct lvp_device *pdevice = pipeline->device;
387bf215546Sopenharmony_ci   gl_shader_stage stage = vk_to_mesa_shader_stage(sinfo->stage);
388bf215546Sopenharmony_ci   const nir_shader_compiler_options *drv_options = pdevice->pscreen->get_compiler_options(pipeline->device->pscreen, PIPE_SHADER_IR_NIR, st_shader_stage_to_ptarget(stage));
389bf215546Sopenharmony_ci   VkResult result;
390bf215546Sopenharmony_ci   nir_shader *nir;
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_ci   const struct spirv_to_nir_options spirv_options = {
393bf215546Sopenharmony_ci      .environment = NIR_SPIRV_VULKAN,
394bf215546Sopenharmony_ci      .caps = {
395bf215546Sopenharmony_ci         .float64 = (pdevice->pscreen->get_param(pdevice->pscreen, PIPE_CAP_DOUBLES) == 1),
396bf215546Sopenharmony_ci         .int16 = true,
397bf215546Sopenharmony_ci         .int64 = (pdevice->pscreen->get_param(pdevice->pscreen, PIPE_CAP_INT64) == 1),
398bf215546Sopenharmony_ci         .tessellation = true,
399bf215546Sopenharmony_ci         .float_controls = true,
400bf215546Sopenharmony_ci         .image_ms_array = true,
401bf215546Sopenharmony_ci         .image_read_without_format = true,
402bf215546Sopenharmony_ci         .image_write_without_format = true,
403bf215546Sopenharmony_ci         .storage_image_ms = true,
404bf215546Sopenharmony_ci         .geometry_streams = true,
405bf215546Sopenharmony_ci         .storage_8bit = true,
406bf215546Sopenharmony_ci         .storage_16bit = true,
407bf215546Sopenharmony_ci         .variable_pointers = true,
408bf215546Sopenharmony_ci         .stencil_export = true,
409bf215546Sopenharmony_ci         .post_depth_coverage = true,
410bf215546Sopenharmony_ci         .transform_feedback = true,
411bf215546Sopenharmony_ci         .device_group = true,
412bf215546Sopenharmony_ci         .draw_parameters = true,
413bf215546Sopenharmony_ci         .shader_viewport_index_layer = true,
414bf215546Sopenharmony_ci         .multiview = true,
415bf215546Sopenharmony_ci         .physical_storage_buffer_address = true,
416bf215546Sopenharmony_ci         .int64_atomics = true,
417bf215546Sopenharmony_ci         .subgroup_arithmetic = true,
418bf215546Sopenharmony_ci         .subgroup_basic = true,
419bf215546Sopenharmony_ci         .subgroup_ballot = true,
420bf215546Sopenharmony_ci         .subgroup_quad = true,
421bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR >= 10
422bf215546Sopenharmony_ci         .subgroup_shuffle = true,
423bf215546Sopenharmony_ci#endif
424bf215546Sopenharmony_ci         .subgroup_vote = true,
425bf215546Sopenharmony_ci         .vk_memory_model = true,
426bf215546Sopenharmony_ci         .vk_memory_model_device_scope = true,
427bf215546Sopenharmony_ci         .int8 = true,
428bf215546Sopenharmony_ci         .float16 = true,
429bf215546Sopenharmony_ci         .demote_to_helper_invocation = true,
430bf215546Sopenharmony_ci      },
431bf215546Sopenharmony_ci      .ubo_addr_format = nir_address_format_32bit_index_offset,
432bf215546Sopenharmony_ci      .ssbo_addr_format = nir_address_format_32bit_index_offset,
433bf215546Sopenharmony_ci      .phys_ssbo_addr_format = nir_address_format_64bit_global,
434bf215546Sopenharmony_ci      .push_const_addr_format = nir_address_format_logical,
435bf215546Sopenharmony_ci      .shared_addr_format = nir_address_format_32bit_offset,
436bf215546Sopenharmony_ci   };
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci   result = vk_pipeline_shader_stage_to_nir(&pdevice->vk, sinfo,
439bf215546Sopenharmony_ci                                            &spirv_options, drv_options,
440bf215546Sopenharmony_ci                                            NULL, &nir);
441bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
442bf215546Sopenharmony_ci      return result;
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ci   if (nir->info.stage != MESA_SHADER_TESS_CTRL)
445bf215546Sopenharmony_ci      NIR_PASS_V(nir, remove_scoped_barriers, nir->info.stage == MESA_SHADER_COMPUTE);
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_ci   const struct nir_lower_sysvals_to_varyings_options sysvals_to_varyings = {
448bf215546Sopenharmony_ci      .frag_coord = true,
449bf215546Sopenharmony_ci      .point_coord = true,
450bf215546Sopenharmony_ci   };
451bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_sysvals_to_varyings, &sysvals_to_varyings);
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci   struct nir_lower_subgroups_options subgroup_opts = {0};
454bf215546Sopenharmony_ci   subgroup_opts.lower_quad = true;
455bf215546Sopenharmony_ci   subgroup_opts.ballot_components = 1;
456bf215546Sopenharmony_ci   subgroup_opts.ballot_bit_size = 32;
457bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_subgroups, &subgroup_opts);
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_ci   if (stage == MESA_SHADER_FRAGMENT)
460bf215546Sopenharmony_ci      lvp_lower_input_attachments(nir, false);
461bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_is_helper_invocation);
462bf215546Sopenharmony_ci   NIR_PASS_V(nir, lower_demote);
463bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_system_values);
464bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_compute_system_values, NULL);
465bf215546Sopenharmony_ci
466bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_remove_dead_variables,
467bf215546Sopenharmony_ci              nir_var_uniform | nir_var_image, NULL);
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci   scan_pipeline_info(pipeline, nir);
470bf215546Sopenharmony_ci
471bf215546Sopenharmony_ci   optimize(nir);
472bf215546Sopenharmony_ci   lvp_lower_pipeline_layout(pipeline->device, pipeline->layout, nir);
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_io_to_temporaries, nir_shader_get_entrypoint(nir), true, true);
475bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_split_var_copies);
476bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_global_vars_to_local);
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_push_const,
479bf215546Sopenharmony_ci              nir_address_format_32bit_offset);
480bf215546Sopenharmony_ci
481bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_explicit_io,
482bf215546Sopenharmony_ci              nir_var_mem_ubo | nir_var_mem_ssbo,
483bf215546Sopenharmony_ci              nir_address_format_32bit_index_offset);
484bf215546Sopenharmony_ci
485bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_lower_explicit_io,
486bf215546Sopenharmony_ci              nir_var_mem_global,
487bf215546Sopenharmony_ci              nir_address_format_64bit_global);
488bf215546Sopenharmony_ci
489bf215546Sopenharmony_ci   if (nir->info.stage == MESA_SHADER_COMPUTE) {
490bf215546Sopenharmony_ci      NIR_PASS_V(nir, nir_lower_vars_to_explicit_types, nir_var_mem_shared, shared_var_info);
491bf215546Sopenharmony_ci      NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_mem_shared, nir_address_format_32bit_offset);
492bf215546Sopenharmony_ci   }
493bf215546Sopenharmony_ci
494bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_shader_temp, NULL);
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci   if (nir->info.stage == MESA_SHADER_VERTEX ||
497bf215546Sopenharmony_ci       nir->info.stage == MESA_SHADER_GEOMETRY) {
498bf215546Sopenharmony_ci      NIR_PASS_V(nir, nir_lower_io_arrays_to_elements_no_indirects, false);
499bf215546Sopenharmony_ci   } else if (nir->info.stage == MESA_SHADER_FRAGMENT) {
500bf215546Sopenharmony_ci      NIR_PASS_V(nir, nir_lower_io_arrays_to_elements_no_indirects, true);
501bf215546Sopenharmony_ci   }
502bf215546Sopenharmony_ci
503bf215546Sopenharmony_ci   // TODO: also optimize the tex srcs. see radeonSI for reference */
504bf215546Sopenharmony_ci   /* Skip if there are potentially conflicting rounding modes */
505bf215546Sopenharmony_ci   struct nir_fold_16bit_tex_image_options fold_16bit_options = {
506bf215546Sopenharmony_ci      .rounding_mode = nir_rounding_mode_undef,
507bf215546Sopenharmony_ci      .fold_tex_dest = true,
508bf215546Sopenharmony_ci   };
509bf215546Sopenharmony_ci   NIR_PASS_V(nir, nir_fold_16bit_tex_image, &fold_16bit_options);
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   lvp_shader_optimize(nir);
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci   nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));
514bf215546Sopenharmony_ci
515bf215546Sopenharmony_ci   if (nir->info.stage != MESA_SHADER_VERTEX)
516bf215546Sopenharmony_ci      nir_assign_io_var_locations(nir, nir_var_shader_in, &nir->num_inputs, nir->info.stage);
517bf215546Sopenharmony_ci   else {
518bf215546Sopenharmony_ci      nir->num_inputs = util_last_bit64(nir->info.inputs_read);
519bf215546Sopenharmony_ci      nir_foreach_shader_in_variable(var, nir) {
520bf215546Sopenharmony_ci         var->data.driver_location = var->data.location - VERT_ATTRIB_GENERIC0;
521bf215546Sopenharmony_ci      }
522bf215546Sopenharmony_ci   }
523bf215546Sopenharmony_ci   nir_assign_io_var_locations(nir, nir_var_shader_out, &nir->num_outputs,
524bf215546Sopenharmony_ci                               nir->info.stage);
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_ci   nir_function_impl *impl = nir_shader_get_entrypoint(nir);
527bf215546Sopenharmony_ci   if (impl->ssa_alloc > 100) //skip for small shaders
528bf215546Sopenharmony_ci      pipeline->inlines[stage].must_inline = lvp_find_inlinable_uniforms(pipeline, nir);
529bf215546Sopenharmony_ci   pipeline->pipeline_nir[stage] = nir;
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   return VK_SUCCESS;
532bf215546Sopenharmony_ci}
533bf215546Sopenharmony_ci
534bf215546Sopenharmony_cistatic void
535bf215546Sopenharmony_cimerge_tess_info(struct shader_info *tes_info,
536bf215546Sopenharmony_ci                const struct shader_info *tcs_info)
537bf215546Sopenharmony_ci{
538bf215546Sopenharmony_ci   /* The Vulkan 1.0.38 spec, section 21.1 Tessellator says:
539bf215546Sopenharmony_ci    *
540bf215546Sopenharmony_ci    *    "PointMode. Controls generation of points rather than triangles
541bf215546Sopenharmony_ci    *     or lines. This functionality defaults to disabled, and is
542bf215546Sopenharmony_ci    *     enabled if either shader stage includes the execution mode.
543bf215546Sopenharmony_ci    *
544bf215546Sopenharmony_ci    * and about Triangles, Quads, IsoLines, VertexOrderCw, VertexOrderCcw,
545bf215546Sopenharmony_ci    * PointMode, SpacingEqual, SpacingFractionalEven, SpacingFractionalOdd,
546bf215546Sopenharmony_ci    * and OutputVertices, it says:
547bf215546Sopenharmony_ci    *
548bf215546Sopenharmony_ci    *    "One mode must be set in at least one of the tessellation
549bf215546Sopenharmony_ci    *     shader stages."
550bf215546Sopenharmony_ci    *
551bf215546Sopenharmony_ci    * So, the fields can be set in either the TCS or TES, but they must
552bf215546Sopenharmony_ci    * agree if set in both.  Our backend looks at TES, so bitwise-or in
553bf215546Sopenharmony_ci    * the values from the TCS.
554bf215546Sopenharmony_ci    */
555bf215546Sopenharmony_ci   assert(tcs_info->tess.tcs_vertices_out == 0 ||
556bf215546Sopenharmony_ci          tes_info->tess.tcs_vertices_out == 0 ||
557bf215546Sopenharmony_ci          tcs_info->tess.tcs_vertices_out == tes_info->tess.tcs_vertices_out);
558bf215546Sopenharmony_ci   tes_info->tess.tcs_vertices_out |= tcs_info->tess.tcs_vertices_out;
559bf215546Sopenharmony_ci
560bf215546Sopenharmony_ci   assert(tcs_info->tess.spacing == TESS_SPACING_UNSPECIFIED ||
561bf215546Sopenharmony_ci          tes_info->tess.spacing == TESS_SPACING_UNSPECIFIED ||
562bf215546Sopenharmony_ci          tcs_info->tess.spacing == tes_info->tess.spacing);
563bf215546Sopenharmony_ci   tes_info->tess.spacing |= tcs_info->tess.spacing;
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_ci   assert(tcs_info->tess._primitive_mode == 0 ||
566bf215546Sopenharmony_ci          tes_info->tess._primitive_mode == 0 ||
567bf215546Sopenharmony_ci          tcs_info->tess._primitive_mode == tes_info->tess._primitive_mode);
568bf215546Sopenharmony_ci   tes_info->tess._primitive_mode |= tcs_info->tess._primitive_mode;
569bf215546Sopenharmony_ci   tes_info->tess.ccw |= tcs_info->tess.ccw;
570bf215546Sopenharmony_ci   tes_info->tess.point_mode |= tcs_info->tess.point_mode;
571bf215546Sopenharmony_ci}
572bf215546Sopenharmony_ci
573bf215546Sopenharmony_cistatic void
574bf215546Sopenharmony_cilvp_pipeline_xfb_init(struct lvp_pipeline *pipeline)
575bf215546Sopenharmony_ci{
576bf215546Sopenharmony_ci   gl_shader_stage stage = MESA_SHADER_VERTEX;
577bf215546Sopenharmony_ci   if (pipeline->pipeline_nir[MESA_SHADER_GEOMETRY])
578bf215546Sopenharmony_ci      stage = MESA_SHADER_GEOMETRY;
579bf215546Sopenharmony_ci   else if (pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL])
580bf215546Sopenharmony_ci      stage = MESA_SHADER_TESS_EVAL;
581bf215546Sopenharmony_ci   pipeline->last_vertex = stage;
582bf215546Sopenharmony_ci
583bf215546Sopenharmony_ci   nir_xfb_info *xfb_info = pipeline->pipeline_nir[stage]->xfb_info;
584bf215546Sopenharmony_ci   if (xfb_info) {
585bf215546Sopenharmony_ci      uint8_t output_mapping[VARYING_SLOT_TESS_MAX];
586bf215546Sopenharmony_ci      memset(output_mapping, 0, sizeof(output_mapping));
587bf215546Sopenharmony_ci
588bf215546Sopenharmony_ci      nir_foreach_shader_out_variable(var, pipeline->pipeline_nir[stage]) {
589bf215546Sopenharmony_ci         unsigned slots = var->data.compact ? DIV_ROUND_UP(glsl_get_length(var->type), 4)
590bf215546Sopenharmony_ci                                            : glsl_count_attribute_slots(var->type, false);
591bf215546Sopenharmony_ci         for (unsigned i = 0; i < slots; i++)
592bf215546Sopenharmony_ci            output_mapping[var->data.location + i] = var->data.driver_location + i;
593bf215546Sopenharmony_ci      }
594bf215546Sopenharmony_ci
595bf215546Sopenharmony_ci      pipeline->stream_output.num_outputs = xfb_info->output_count;
596bf215546Sopenharmony_ci      for (unsigned i = 0; i < PIPE_MAX_SO_BUFFERS; i++) {
597bf215546Sopenharmony_ci         if (xfb_info->buffers_written & (1 << i)) {
598bf215546Sopenharmony_ci            pipeline->stream_output.stride[i] = xfb_info->buffers[i].stride / 4;
599bf215546Sopenharmony_ci         }
600bf215546Sopenharmony_ci      }
601bf215546Sopenharmony_ci      for (unsigned i = 0; i < xfb_info->output_count; i++) {
602bf215546Sopenharmony_ci         pipeline->stream_output.output[i].output_buffer = xfb_info->outputs[i].buffer;
603bf215546Sopenharmony_ci         pipeline->stream_output.output[i].dst_offset = xfb_info->outputs[i].offset / 4;
604bf215546Sopenharmony_ci         pipeline->stream_output.output[i].register_index = output_mapping[xfb_info->outputs[i].location];
605bf215546Sopenharmony_ci         pipeline->stream_output.output[i].num_components = util_bitcount(xfb_info->outputs[i].component_mask);
606bf215546Sopenharmony_ci         pipeline->stream_output.output[i].start_component = ffs(xfb_info->outputs[i].component_mask) - 1;
607bf215546Sopenharmony_ci         pipeline->stream_output.output[i].stream = xfb_info->buffer_to_stream[xfb_info->outputs[i].buffer];
608bf215546Sopenharmony_ci      }
609bf215546Sopenharmony_ci
610bf215546Sopenharmony_ci   }
611bf215546Sopenharmony_ci}
612bf215546Sopenharmony_ci
613bf215546Sopenharmony_civoid *
614bf215546Sopenharmony_cilvp_pipeline_compile_stage(struct lvp_pipeline *pipeline, nir_shader *nir)
615bf215546Sopenharmony_ci{
616bf215546Sopenharmony_ci   struct lvp_device *device = pipeline->device;
617bf215546Sopenharmony_ci   if (nir->info.stage == MESA_SHADER_COMPUTE) {
618bf215546Sopenharmony_ci      struct pipe_compute_state shstate = {0};
619bf215546Sopenharmony_ci      shstate.prog = nir;
620bf215546Sopenharmony_ci      shstate.ir_type = PIPE_SHADER_IR_NIR;
621bf215546Sopenharmony_ci      shstate.req_local_mem = nir->info.shared_size;
622bf215546Sopenharmony_ci      return device->queue.ctx->create_compute_state(device->queue.ctx, &shstate);
623bf215546Sopenharmony_ci   } else {
624bf215546Sopenharmony_ci      struct pipe_shader_state shstate = {0};
625bf215546Sopenharmony_ci      shstate.type = PIPE_SHADER_IR_NIR;
626bf215546Sopenharmony_ci      shstate.ir.nir = nir;
627bf215546Sopenharmony_ci      if (nir->info.stage == pipeline->last_vertex)
628bf215546Sopenharmony_ci         memcpy(&shstate.stream_output, &pipeline->stream_output, sizeof(shstate.stream_output));
629bf215546Sopenharmony_ci
630bf215546Sopenharmony_ci      switch (nir->info.stage) {
631bf215546Sopenharmony_ci      case MESA_SHADER_FRAGMENT:
632bf215546Sopenharmony_ci         return device->queue.ctx->create_fs_state(device->queue.ctx, &shstate);
633bf215546Sopenharmony_ci      case MESA_SHADER_VERTEX:
634bf215546Sopenharmony_ci         return device->queue.ctx->create_vs_state(device->queue.ctx, &shstate);
635bf215546Sopenharmony_ci      case MESA_SHADER_GEOMETRY:
636bf215546Sopenharmony_ci         return device->queue.ctx->create_gs_state(device->queue.ctx, &shstate);
637bf215546Sopenharmony_ci      case MESA_SHADER_TESS_CTRL:
638bf215546Sopenharmony_ci         return device->queue.ctx->create_tcs_state(device->queue.ctx, &shstate);
639bf215546Sopenharmony_ci      case MESA_SHADER_TESS_EVAL:
640bf215546Sopenharmony_ci         return device->queue.ctx->create_tes_state(device->queue.ctx, &shstate);
641bf215546Sopenharmony_ci      default:
642bf215546Sopenharmony_ci         unreachable("illegal shader");
643bf215546Sopenharmony_ci         break;
644bf215546Sopenharmony_ci      }
645bf215546Sopenharmony_ci   }
646bf215546Sopenharmony_ci   return NULL;
647bf215546Sopenharmony_ci}
648bf215546Sopenharmony_ci
649bf215546Sopenharmony_civoid *
650bf215546Sopenharmony_cilvp_pipeline_compile(struct lvp_pipeline *pipeline, nir_shader *nir)
651bf215546Sopenharmony_ci{
652bf215546Sopenharmony_ci   struct lvp_device *device = pipeline->device;
653bf215546Sopenharmony_ci   device->physical_device->pscreen->finalize_nir(device->physical_device->pscreen, nir);
654bf215546Sopenharmony_ci   return lvp_pipeline_compile_stage(pipeline, nir);
655bf215546Sopenharmony_ci}
656bf215546Sopenharmony_ci
657bf215546Sopenharmony_ci#ifndef NDEBUG
658bf215546Sopenharmony_cistatic bool
659bf215546Sopenharmony_cilayouts_equal(const struct lvp_descriptor_set_layout *a, const struct lvp_descriptor_set_layout *b)
660bf215546Sopenharmony_ci{
661bf215546Sopenharmony_ci   const uint8_t *pa = (const uint8_t*)a, *pb = (const uint8_t*)b;
662bf215546Sopenharmony_ci   uint32_t hash_start_offset = sizeof(struct vk_descriptor_set_layout);
663bf215546Sopenharmony_ci   uint32_t binding_offset = offsetof(struct lvp_descriptor_set_layout, binding);
664bf215546Sopenharmony_ci   /* base equal */
665bf215546Sopenharmony_ci   if (memcmp(pa + hash_start_offset, pb + hash_start_offset, binding_offset - hash_start_offset))
666bf215546Sopenharmony_ci      return false;
667bf215546Sopenharmony_ci
668bf215546Sopenharmony_ci   /* bindings equal */
669bf215546Sopenharmony_ci   if (a->binding_count != b->binding_count)
670bf215546Sopenharmony_ci      return false;
671bf215546Sopenharmony_ci   size_t binding_size = a->binding_count * sizeof(struct lvp_descriptor_set_binding_layout);
672bf215546Sopenharmony_ci   const struct lvp_descriptor_set_binding_layout *la = a->binding;
673bf215546Sopenharmony_ci   const struct lvp_descriptor_set_binding_layout *lb = b->binding;
674bf215546Sopenharmony_ci   if (memcmp(la, lb, binding_size)) {
675bf215546Sopenharmony_ci      for (unsigned i = 0; i < a->binding_count; i++) {
676bf215546Sopenharmony_ci         if (memcmp(&la[i], &lb[i], offsetof(struct lvp_descriptor_set_binding_layout, immutable_samplers)))
677bf215546Sopenharmony_ci            return false;
678bf215546Sopenharmony_ci      }
679bf215546Sopenharmony_ci   }
680bf215546Sopenharmony_ci
681bf215546Sopenharmony_ci   /* immutable sampler equal */
682bf215546Sopenharmony_ci   if (a->immutable_sampler_count != b->immutable_sampler_count)
683bf215546Sopenharmony_ci      return false;
684bf215546Sopenharmony_ci   if (a->immutable_sampler_count) {
685bf215546Sopenharmony_ci      size_t sampler_size = a->immutable_sampler_count * sizeof(struct lvp_sampler *);
686bf215546Sopenharmony_ci      if (memcmp(pa + binding_offset + binding_size, pb + binding_offset + binding_size, sampler_size)) {
687bf215546Sopenharmony_ci         struct lvp_sampler **sa = (struct lvp_sampler **)(pa + binding_offset);
688bf215546Sopenharmony_ci         struct lvp_sampler **sb = (struct lvp_sampler **)(pb + binding_offset);
689bf215546Sopenharmony_ci         for (unsigned i = 0; i < a->immutable_sampler_count; i++) {
690bf215546Sopenharmony_ci            if (memcmp(sa[i], sb[i], sizeof(struct lvp_sampler)))
691bf215546Sopenharmony_ci               return false;
692bf215546Sopenharmony_ci         }
693bf215546Sopenharmony_ci      }
694bf215546Sopenharmony_ci   }
695bf215546Sopenharmony_ci   return true;
696bf215546Sopenharmony_ci}
697bf215546Sopenharmony_ci#endif
698bf215546Sopenharmony_ci
699bf215546Sopenharmony_cistatic void
700bf215546Sopenharmony_cimerge_layouts(struct lvp_pipeline *dst, struct lvp_pipeline_layout *src)
701bf215546Sopenharmony_ci{
702bf215546Sopenharmony_ci   if (!src)
703bf215546Sopenharmony_ci      return;
704bf215546Sopenharmony_ci   if (!dst->layout) {
705bf215546Sopenharmony_ci      /* no layout created yet: copy onto ralloc ctx allocation for auto-free */
706bf215546Sopenharmony_ci      dst->layout = ralloc(dst->mem_ctx, struct lvp_pipeline_layout);
707bf215546Sopenharmony_ci      memcpy(dst->layout, src, sizeof(struct lvp_pipeline_layout));
708bf215546Sopenharmony_ci      return;
709bf215546Sopenharmony_ci   }
710bf215546Sopenharmony_ci#ifndef NDEBUG
711bf215546Sopenharmony_ci   /* verify that layouts match */
712bf215546Sopenharmony_ci   const struct lvp_pipeline_layout *smaller = dst->layout->vk.set_count < src->vk.set_count ? dst->layout : src;
713bf215546Sopenharmony_ci   const struct lvp_pipeline_layout *bigger = smaller == dst->layout ? src : dst->layout;
714bf215546Sopenharmony_ci   for (unsigned i = 0; i < smaller->vk.set_count; i++) {
715bf215546Sopenharmony_ci      if (!smaller->vk.set_layouts[i] || !bigger->vk.set_layouts[i] ||
716bf215546Sopenharmony_ci          smaller->vk.set_layouts[i] == bigger->vk.set_layouts[i])
717bf215546Sopenharmony_ci         continue;
718bf215546Sopenharmony_ci
719bf215546Sopenharmony_ci      const struct lvp_descriptor_set_layout *smaller_set_layout =
720bf215546Sopenharmony_ci         vk_to_lvp_descriptor_set_layout(smaller->vk.set_layouts[i]);
721bf215546Sopenharmony_ci      const struct lvp_descriptor_set_layout *bigger_set_layout =
722bf215546Sopenharmony_ci         vk_to_lvp_descriptor_set_layout(bigger->vk.set_layouts[i]);
723bf215546Sopenharmony_ci
724bf215546Sopenharmony_ci      assert(!smaller_set_layout->binding_count ||
725bf215546Sopenharmony_ci             !bigger_set_layout->binding_count ||
726bf215546Sopenharmony_ci             layouts_equal(smaller_set_layout, bigger_set_layout));
727bf215546Sopenharmony_ci   }
728bf215546Sopenharmony_ci#endif
729bf215546Sopenharmony_ci   for (unsigned i = 0; i < src->vk.set_count; i++) {
730bf215546Sopenharmony_ci      if (!dst->layout->vk.set_layouts[i])
731bf215546Sopenharmony_ci         dst->layout->vk.set_layouts[i] = src->vk.set_layouts[i];
732bf215546Sopenharmony_ci   }
733bf215546Sopenharmony_ci   dst->layout->vk.set_count = MAX2(dst->layout->vk.set_count,
734bf215546Sopenharmony_ci                                    src->vk.set_count);
735bf215546Sopenharmony_ci   dst->layout->push_constant_size += src->push_constant_size;
736bf215546Sopenharmony_ci   dst->layout->push_constant_stages |= src->push_constant_stages;
737bf215546Sopenharmony_ci}
738bf215546Sopenharmony_ci
739bf215546Sopenharmony_cistatic VkResult
740bf215546Sopenharmony_cilvp_graphics_pipeline_init(struct lvp_pipeline *pipeline,
741bf215546Sopenharmony_ci                           struct lvp_device *device,
742bf215546Sopenharmony_ci                           struct lvp_pipeline_cache *cache,
743bf215546Sopenharmony_ci                           const VkGraphicsPipelineCreateInfo *pCreateInfo)
744bf215546Sopenharmony_ci{
745bf215546Sopenharmony_ci   VkResult result;
746bf215546Sopenharmony_ci
747bf215546Sopenharmony_ci   const VkGraphicsPipelineLibraryCreateInfoEXT *libinfo = vk_find_struct_const(pCreateInfo,
748bf215546Sopenharmony_ci                                                                                GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT);
749bf215546Sopenharmony_ci   const VkPipelineLibraryCreateInfoKHR *libstate = vk_find_struct_const(pCreateInfo,
750bf215546Sopenharmony_ci                                                                         PIPELINE_LIBRARY_CREATE_INFO_KHR);
751bf215546Sopenharmony_ci   const VkGraphicsPipelineLibraryFlagsEXT layout_stages = VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
752bf215546Sopenharmony_ci                                                           VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
753bf215546Sopenharmony_ci   if (libinfo)
754bf215546Sopenharmony_ci      pipeline->stages = libinfo->flags;
755bf215546Sopenharmony_ci   else if (!libstate)
756bf215546Sopenharmony_ci      pipeline->stages = VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT |
757bf215546Sopenharmony_ci                         VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
758bf215546Sopenharmony_ci                         VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT |
759bf215546Sopenharmony_ci                         VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT;
760bf215546Sopenharmony_ci   pipeline->mem_ctx = ralloc_context(NULL);
761bf215546Sopenharmony_ci
762bf215546Sopenharmony_ci   if (pCreateInfo->flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR)
763bf215546Sopenharmony_ci      pipeline->library = true;
764bf215546Sopenharmony_ci
765bf215546Sopenharmony_ci   struct lvp_pipeline_layout *layout = lvp_pipeline_layout_from_handle(pCreateInfo->layout);
766bf215546Sopenharmony_ci   if (layout)
767bf215546Sopenharmony_ci      vk_pipeline_layout_ref(&layout->vk);
768bf215546Sopenharmony_ci
769bf215546Sopenharmony_ci   if (!layout || !(layout->vk.create_flags & VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT))
770bf215546Sopenharmony_ci      /* this is a regular pipeline with no partials: directly reuse */
771bf215546Sopenharmony_ci      pipeline->layout = layout;
772bf215546Sopenharmony_ci   else if (pipeline->stages & layout_stages) {
773bf215546Sopenharmony_ci      if ((pipeline->stages & layout_stages) == layout_stages)
774bf215546Sopenharmony_ci         /* this has all the layout stages: directly reuse */
775bf215546Sopenharmony_ci         pipeline->layout = layout;
776bf215546Sopenharmony_ci      else {
777bf215546Sopenharmony_ci         /* this is a partial: copy for later merging to avoid modifying another layout */
778bf215546Sopenharmony_ci         merge_layouts(pipeline, layout);
779bf215546Sopenharmony_ci      }
780bf215546Sopenharmony_ci   }
781bf215546Sopenharmony_ci
782bf215546Sopenharmony_ci   if (libstate) {
783bf215546Sopenharmony_ci      for (unsigned i = 0; i < libstate->libraryCount; i++) {
784bf215546Sopenharmony_ci         LVP_FROM_HANDLE(lvp_pipeline, p, libstate->pLibraries[i]);
785bf215546Sopenharmony_ci         vk_graphics_pipeline_state_merge(&pipeline->graphics_state,
786bf215546Sopenharmony_ci                                          &p->graphics_state);
787bf215546Sopenharmony_ci         if (p->stages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
788bf215546Sopenharmony_ci            pipeline->line_smooth = p->line_smooth;
789bf215546Sopenharmony_ci            pipeline->disable_multisample = p->disable_multisample;
790bf215546Sopenharmony_ci            pipeline->line_rectangular = p->line_rectangular;
791bf215546Sopenharmony_ci            pipeline->last_vertex = p->last_vertex;
792bf215546Sopenharmony_ci            memcpy(&pipeline->stream_output, &p->stream_output, sizeof(p->stream_output));
793bf215546Sopenharmony_ci            memcpy(&pipeline->access, &p->access, sizeof(p->access));
794bf215546Sopenharmony_ci         }
795bf215546Sopenharmony_ci         if (p->stages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT)
796bf215546Sopenharmony_ci            pipeline->force_min_sample = p->force_min_sample;
797bf215546Sopenharmony_ci         if (p->stages & layout_stages) {
798bf215546Sopenharmony_ci            if (!layout || (layout->vk.create_flags & VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT))
799bf215546Sopenharmony_ci               merge_layouts(pipeline, p->layout);
800bf215546Sopenharmony_ci         }
801bf215546Sopenharmony_ci         pipeline->stages |= p->stages;
802bf215546Sopenharmony_ci      }
803bf215546Sopenharmony_ci   }
804bf215546Sopenharmony_ci
805bf215546Sopenharmony_ci   result = vk_graphics_pipeline_state_fill(&device->vk,
806bf215546Sopenharmony_ci                                            &pipeline->graphics_state,
807bf215546Sopenharmony_ci                                            pCreateInfo, NULL, NULL, NULL,
808bf215546Sopenharmony_ci                                            VK_SYSTEM_ALLOCATION_SCOPE_OBJECT,
809bf215546Sopenharmony_ci                                            &pipeline->state_data);
810bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
811bf215546Sopenharmony_ci      return result;
812bf215546Sopenharmony_ci
813bf215546Sopenharmony_ci   assert(pipeline->library || pipeline->stages == (VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT |
814bf215546Sopenharmony_ci                                                    VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
815bf215546Sopenharmony_ci                                                    VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT |
816bf215546Sopenharmony_ci                                                    VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT));
817bf215546Sopenharmony_ci
818bf215546Sopenharmony_ci   pipeline->device = device;
819bf215546Sopenharmony_ci
820bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
821bf215546Sopenharmony_ci      const VkPipelineShaderStageCreateInfo *sinfo = &pCreateInfo->pStages[i];
822bf215546Sopenharmony_ci      gl_shader_stage stage = vk_to_mesa_shader_stage(sinfo->stage);
823bf215546Sopenharmony_ci      if (stage == MESA_SHADER_FRAGMENT) {
824bf215546Sopenharmony_ci         if (!(pipeline->stages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT))
825bf215546Sopenharmony_ci            continue;
826bf215546Sopenharmony_ci      } else {
827bf215546Sopenharmony_ci         if (!(pipeline->stages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT))
828bf215546Sopenharmony_ci            continue;
829bf215546Sopenharmony_ci      }
830bf215546Sopenharmony_ci      result = lvp_shader_compile_to_ir(pipeline, sinfo);
831bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
832bf215546Sopenharmony_ci         goto fail;
833bf215546Sopenharmony_ci
834bf215546Sopenharmony_ci      switch (stage) {
835bf215546Sopenharmony_ci      case MESA_SHADER_GEOMETRY:
836bf215546Sopenharmony_ci         pipeline->gs_output_lines = pipeline->pipeline_nir[MESA_SHADER_GEOMETRY] &&
837bf215546Sopenharmony_ci                                     pipeline->pipeline_nir[MESA_SHADER_GEOMETRY]->info.gs.output_primitive == SHADER_PRIM_LINES;
838bf215546Sopenharmony_ci         break;
839bf215546Sopenharmony_ci      case MESA_SHADER_FRAGMENT:
840bf215546Sopenharmony_ci         if (pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]->info.fs.uses_sample_shading)
841bf215546Sopenharmony_ci            pipeline->force_min_sample = true;
842bf215546Sopenharmony_ci         break;
843bf215546Sopenharmony_ci      default: break;
844bf215546Sopenharmony_ci      }
845bf215546Sopenharmony_ci   }
846bf215546Sopenharmony_ci   if (pCreateInfo->stageCount && pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL]) {
847bf215546Sopenharmony_ci      nir_lower_patch_vertices(pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL], pipeline->pipeline_nir[MESA_SHADER_TESS_CTRL]->info.tess.tcs_vertices_out, NULL);
848bf215546Sopenharmony_ci      merge_tess_info(&pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL]->info, &pipeline->pipeline_nir[MESA_SHADER_TESS_CTRL]->info);
849bf215546Sopenharmony_ci      if (pipeline->graphics_state.ts->domain_origin == VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT)
850bf215546Sopenharmony_ci         pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL]->info.tess.ccw = !pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL]->info.tess.ccw;
851bf215546Sopenharmony_ci   }
852bf215546Sopenharmony_ci   if (libstate) {
853bf215546Sopenharmony_ci       for (unsigned i = 0; i < libstate->libraryCount; i++) {
854bf215546Sopenharmony_ci          LVP_FROM_HANDLE(lvp_pipeline, p, libstate->pLibraries[i]);
855bf215546Sopenharmony_ci          if (p->stages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) {
856bf215546Sopenharmony_ci             if (p->pipeline_nir[MESA_SHADER_FRAGMENT])
857bf215546Sopenharmony_ci                pipeline->pipeline_nir[MESA_SHADER_FRAGMENT] = nir_shader_clone(pipeline->mem_ctx, p->pipeline_nir[MESA_SHADER_FRAGMENT]);
858bf215546Sopenharmony_ci          }
859bf215546Sopenharmony_ci          if (p->stages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
860bf215546Sopenharmony_ci             for (unsigned j = MESA_SHADER_VERTEX; j < MESA_SHADER_FRAGMENT; j++) {
861bf215546Sopenharmony_ci                if (p->pipeline_nir[j])
862bf215546Sopenharmony_ci                   pipeline->pipeline_nir[j] = nir_shader_clone(pipeline->mem_ctx, p->pipeline_nir[j]);
863bf215546Sopenharmony_ci             }
864bf215546Sopenharmony_ci          }
865bf215546Sopenharmony_ci       }
866bf215546Sopenharmony_ci   } else if (pipeline->stages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
867bf215546Sopenharmony_ci      const struct vk_rasterization_state *rs = pipeline->graphics_state.rs;
868bf215546Sopenharmony_ci      if (rs) {
869bf215546Sopenharmony_ci         /* always draw bresenham if !smooth */
870bf215546Sopenharmony_ci         pipeline->line_smooth = rs->line.mode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
871bf215546Sopenharmony_ci         pipeline->disable_multisample = rs->line.mode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT ||
872bf215546Sopenharmony_ci                                         rs->line.mode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
873bf215546Sopenharmony_ci         pipeline->line_rectangular = rs->line.mode != VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
874bf215546Sopenharmony_ci      } else
875bf215546Sopenharmony_ci         pipeline->line_rectangular = true;
876bf215546Sopenharmony_ci      lvp_pipeline_xfb_init(pipeline);
877bf215546Sopenharmony_ci   }
878bf215546Sopenharmony_ci
879bf215546Sopenharmony_ci   if (!pipeline->library) {
880bf215546Sopenharmony_ci      bool has_fragment_shader = false;
881bf215546Sopenharmony_ci      for (uint32_t i = 0; i < ARRAY_SIZE(pipeline->pipeline_nir); i++) {
882bf215546Sopenharmony_ci         if (!pipeline->pipeline_nir[i])
883bf215546Sopenharmony_ci            continue;
884bf215546Sopenharmony_ci
885bf215546Sopenharmony_ci         gl_shader_stage stage = i;
886bf215546Sopenharmony_ci         assert(stage == pipeline->pipeline_nir[i]->info.stage);
887bf215546Sopenharmony_ci         enum pipe_shader_type pstage = pipe_shader_type_from_mesa(stage);
888bf215546Sopenharmony_ci         if (!pipeline->inlines[stage].can_inline)
889bf215546Sopenharmony_ci            pipeline->shader_cso[pstage] = lvp_pipeline_compile(pipeline,
890bf215546Sopenharmony_ci                                                                nir_shader_clone(NULL, pipeline->pipeline_nir[stage]));
891bf215546Sopenharmony_ci         if (stage == MESA_SHADER_FRAGMENT)
892bf215546Sopenharmony_ci            has_fragment_shader = true;
893bf215546Sopenharmony_ci      }
894bf215546Sopenharmony_ci
895bf215546Sopenharmony_ci      if (has_fragment_shader == false) {
896bf215546Sopenharmony_ci         /* create a dummy fragment shader for this pipeline. */
897bf215546Sopenharmony_ci         nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, NULL,
898bf215546Sopenharmony_ci                                                        "dummy_frag");
899bf215546Sopenharmony_ci
900bf215546Sopenharmony_ci         pipeline->pipeline_nir[MESA_SHADER_FRAGMENT] = b.shader;
901bf215546Sopenharmony_ci         struct pipe_shader_state shstate = {0};
902bf215546Sopenharmony_ci         shstate.type = PIPE_SHADER_IR_NIR;
903bf215546Sopenharmony_ci         shstate.ir.nir = nir_shader_clone(NULL, pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]);
904bf215546Sopenharmony_ci         pipeline->shader_cso[PIPE_SHADER_FRAGMENT] = device->queue.ctx->create_fs_state(device->queue.ctx, &shstate);
905bf215546Sopenharmony_ci      }
906bf215546Sopenharmony_ci   }
907bf215546Sopenharmony_ci   return VK_SUCCESS;
908bf215546Sopenharmony_ci
909bf215546Sopenharmony_cifail:
910bf215546Sopenharmony_ci   for (unsigned i = 0; i < ARRAY_SIZE(pipeline->pipeline_nir); i++) {
911bf215546Sopenharmony_ci      if (pipeline->pipeline_nir[i])
912bf215546Sopenharmony_ci         ralloc_free(pipeline->pipeline_nir[i]);
913bf215546Sopenharmony_ci   }
914bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, pipeline->state_data);
915bf215546Sopenharmony_ci
916bf215546Sopenharmony_ci   return result;
917bf215546Sopenharmony_ci}
918bf215546Sopenharmony_ci
919bf215546Sopenharmony_cistatic VkResult
920bf215546Sopenharmony_cilvp_graphics_pipeline_create(
921bf215546Sopenharmony_ci   VkDevice _device,
922bf215546Sopenharmony_ci   VkPipelineCache _cache,
923bf215546Sopenharmony_ci   const VkGraphicsPipelineCreateInfo *pCreateInfo,
924bf215546Sopenharmony_ci   VkPipeline *pPipeline)
925bf215546Sopenharmony_ci{
926bf215546Sopenharmony_ci   LVP_FROM_HANDLE(lvp_device, device, _device);
927bf215546Sopenharmony_ci   LVP_FROM_HANDLE(lvp_pipeline_cache, cache, _cache);
928bf215546Sopenharmony_ci   struct lvp_pipeline *pipeline;
929bf215546Sopenharmony_ci   VkResult result;
930bf215546Sopenharmony_ci
931bf215546Sopenharmony_ci   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO);
932bf215546Sopenharmony_ci
933bf215546Sopenharmony_ci   pipeline = vk_zalloc(&device->vk.alloc, sizeof(*pipeline), 8,
934bf215546Sopenharmony_ci                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
935bf215546Sopenharmony_ci   if (pipeline == NULL)
936bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
937bf215546Sopenharmony_ci
938bf215546Sopenharmony_ci   vk_object_base_init(&device->vk, &pipeline->base,
939bf215546Sopenharmony_ci                       VK_OBJECT_TYPE_PIPELINE);
940bf215546Sopenharmony_ci   uint64_t t0 = os_time_get_nano();
941bf215546Sopenharmony_ci   result = lvp_graphics_pipeline_init(pipeline, device, cache, pCreateInfo);
942bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
943bf215546Sopenharmony_ci      vk_free(&device->vk.alloc, pipeline);
944bf215546Sopenharmony_ci      return result;
945bf215546Sopenharmony_ci   }
946bf215546Sopenharmony_ci
947bf215546Sopenharmony_ci   VkPipelineCreationFeedbackCreateInfo *feedback = (void*)vk_find_struct_const(pCreateInfo->pNext, PIPELINE_CREATION_FEEDBACK_CREATE_INFO);
948bf215546Sopenharmony_ci   if (feedback) {
949bf215546Sopenharmony_ci      feedback->pPipelineCreationFeedback->duration = os_time_get_nano() - t0;
950bf215546Sopenharmony_ci      feedback->pPipelineCreationFeedback->flags = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT;
951bf215546Sopenharmony_ci      memset(feedback->pPipelineStageCreationFeedbacks, 0, sizeof(VkPipelineCreationFeedback) * feedback->pipelineStageCreationFeedbackCount);
952bf215546Sopenharmony_ci   }
953bf215546Sopenharmony_ci
954bf215546Sopenharmony_ci   *pPipeline = lvp_pipeline_to_handle(pipeline);
955bf215546Sopenharmony_ci
956bf215546Sopenharmony_ci   return VK_SUCCESS;
957bf215546Sopenharmony_ci}
958bf215546Sopenharmony_ci
959bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL lvp_CreateGraphicsPipelines(
960bf215546Sopenharmony_ci   VkDevice                                    _device,
961bf215546Sopenharmony_ci   VkPipelineCache                             pipelineCache,
962bf215546Sopenharmony_ci   uint32_t                                    count,
963bf215546Sopenharmony_ci   const VkGraphicsPipelineCreateInfo*         pCreateInfos,
964bf215546Sopenharmony_ci   const VkAllocationCallbacks*                pAllocator,
965bf215546Sopenharmony_ci   VkPipeline*                                 pPipelines)
966bf215546Sopenharmony_ci{
967bf215546Sopenharmony_ci   VkResult result = VK_SUCCESS;
968bf215546Sopenharmony_ci   unsigned i = 0;
969bf215546Sopenharmony_ci
970bf215546Sopenharmony_ci   for (; i < count; i++) {
971bf215546Sopenharmony_ci      VkResult r = VK_PIPELINE_COMPILE_REQUIRED;
972bf215546Sopenharmony_ci      if (!(pCreateInfos[i].flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT))
973bf215546Sopenharmony_ci         r = lvp_graphics_pipeline_create(_device,
974bf215546Sopenharmony_ci                                          pipelineCache,
975bf215546Sopenharmony_ci                                          &pCreateInfos[i],
976bf215546Sopenharmony_ci                                          &pPipelines[i]);
977bf215546Sopenharmony_ci      if (r != VK_SUCCESS) {
978bf215546Sopenharmony_ci         result = r;
979bf215546Sopenharmony_ci         pPipelines[i] = VK_NULL_HANDLE;
980bf215546Sopenharmony_ci         if (pCreateInfos[i].flags & VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT)
981bf215546Sopenharmony_ci            break;
982bf215546Sopenharmony_ci      }
983bf215546Sopenharmony_ci   }
984bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
985bf215546Sopenharmony_ci      for (; i < count; i++)
986bf215546Sopenharmony_ci         pPipelines[i] = VK_NULL_HANDLE;
987bf215546Sopenharmony_ci   }
988bf215546Sopenharmony_ci
989bf215546Sopenharmony_ci   return result;
990bf215546Sopenharmony_ci}
991bf215546Sopenharmony_ci
992bf215546Sopenharmony_cistatic VkResult
993bf215546Sopenharmony_cilvp_compute_pipeline_init(struct lvp_pipeline *pipeline,
994bf215546Sopenharmony_ci                          struct lvp_device *device,
995bf215546Sopenharmony_ci                          struct lvp_pipeline_cache *cache,
996bf215546Sopenharmony_ci                          const VkComputePipelineCreateInfo *pCreateInfo)
997bf215546Sopenharmony_ci{
998bf215546Sopenharmony_ci   pipeline->device = device;
999bf215546Sopenharmony_ci   pipeline->layout = lvp_pipeline_layout_from_handle(pCreateInfo->layout);
1000bf215546Sopenharmony_ci   vk_pipeline_layout_ref(&pipeline->layout->vk);
1001bf215546Sopenharmony_ci   pipeline->force_min_sample = false;
1002bf215546Sopenharmony_ci
1003bf215546Sopenharmony_ci   pipeline->mem_ctx = ralloc_context(NULL);
1004bf215546Sopenharmony_ci   pipeline->is_compute_pipeline = true;
1005bf215546Sopenharmony_ci
1006bf215546Sopenharmony_ci   VkResult result = lvp_shader_compile_to_ir(pipeline, &pCreateInfo->stage);
1007bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1008bf215546Sopenharmony_ci      return result;
1009bf215546Sopenharmony_ci
1010bf215546Sopenharmony_ci   if (!pipeline->inlines[MESA_SHADER_COMPUTE].can_inline)
1011bf215546Sopenharmony_ci      pipeline->shader_cso[PIPE_SHADER_COMPUTE] = lvp_pipeline_compile(pipeline, nir_shader_clone(NULL, pipeline->pipeline_nir[MESA_SHADER_COMPUTE]));
1012bf215546Sopenharmony_ci   return VK_SUCCESS;
1013bf215546Sopenharmony_ci}
1014bf215546Sopenharmony_ci
1015bf215546Sopenharmony_cistatic VkResult
1016bf215546Sopenharmony_cilvp_compute_pipeline_create(
1017bf215546Sopenharmony_ci   VkDevice _device,
1018bf215546Sopenharmony_ci   VkPipelineCache _cache,
1019bf215546Sopenharmony_ci   const VkComputePipelineCreateInfo *pCreateInfo,
1020bf215546Sopenharmony_ci   VkPipeline *pPipeline)
1021bf215546Sopenharmony_ci{
1022bf215546Sopenharmony_ci   LVP_FROM_HANDLE(lvp_device, device, _device);
1023bf215546Sopenharmony_ci   LVP_FROM_HANDLE(lvp_pipeline_cache, cache, _cache);
1024bf215546Sopenharmony_ci   struct lvp_pipeline *pipeline;
1025bf215546Sopenharmony_ci   VkResult result;
1026bf215546Sopenharmony_ci
1027bf215546Sopenharmony_ci   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO);
1028bf215546Sopenharmony_ci
1029bf215546Sopenharmony_ci   pipeline = vk_zalloc(&device->vk.alloc, sizeof(*pipeline), 8,
1030bf215546Sopenharmony_ci                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1031bf215546Sopenharmony_ci   if (pipeline == NULL)
1032bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1033bf215546Sopenharmony_ci
1034bf215546Sopenharmony_ci   vk_object_base_init(&device->vk, &pipeline->base,
1035bf215546Sopenharmony_ci                       VK_OBJECT_TYPE_PIPELINE);
1036bf215546Sopenharmony_ci   uint64_t t0 = os_time_get_nano();
1037bf215546Sopenharmony_ci   result = lvp_compute_pipeline_init(pipeline, device, cache, pCreateInfo);
1038bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
1039bf215546Sopenharmony_ci      vk_free(&device->vk.alloc, pipeline);
1040bf215546Sopenharmony_ci      return result;
1041bf215546Sopenharmony_ci   }
1042bf215546Sopenharmony_ci
1043bf215546Sopenharmony_ci   const VkPipelineCreationFeedbackCreateInfo *feedback = (void*)vk_find_struct_const(pCreateInfo->pNext, PIPELINE_CREATION_FEEDBACK_CREATE_INFO);
1044bf215546Sopenharmony_ci   if (feedback) {
1045bf215546Sopenharmony_ci      feedback->pPipelineCreationFeedback->duration = os_time_get_nano() - t0;
1046bf215546Sopenharmony_ci      feedback->pPipelineCreationFeedback->flags = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT;
1047bf215546Sopenharmony_ci      memset(feedback->pPipelineStageCreationFeedbacks, 0, sizeof(VkPipelineCreationFeedback) * feedback->pipelineStageCreationFeedbackCount);
1048bf215546Sopenharmony_ci   }
1049bf215546Sopenharmony_ci
1050bf215546Sopenharmony_ci   *pPipeline = lvp_pipeline_to_handle(pipeline);
1051bf215546Sopenharmony_ci
1052bf215546Sopenharmony_ci   return VK_SUCCESS;
1053bf215546Sopenharmony_ci}
1054bf215546Sopenharmony_ci
1055bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL lvp_CreateComputePipelines(
1056bf215546Sopenharmony_ci   VkDevice                                    _device,
1057bf215546Sopenharmony_ci   VkPipelineCache                             pipelineCache,
1058bf215546Sopenharmony_ci   uint32_t                                    count,
1059bf215546Sopenharmony_ci   const VkComputePipelineCreateInfo*          pCreateInfos,
1060bf215546Sopenharmony_ci   const VkAllocationCallbacks*                pAllocator,
1061bf215546Sopenharmony_ci   VkPipeline*                                 pPipelines)
1062bf215546Sopenharmony_ci{
1063bf215546Sopenharmony_ci   VkResult result = VK_SUCCESS;
1064bf215546Sopenharmony_ci   unsigned i = 0;
1065bf215546Sopenharmony_ci
1066bf215546Sopenharmony_ci   for (; i < count; i++) {
1067bf215546Sopenharmony_ci      VkResult r = VK_PIPELINE_COMPILE_REQUIRED;
1068bf215546Sopenharmony_ci      if (!(pCreateInfos[i].flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT))
1069bf215546Sopenharmony_ci         r = lvp_compute_pipeline_create(_device,
1070bf215546Sopenharmony_ci                                         pipelineCache,
1071bf215546Sopenharmony_ci                                         &pCreateInfos[i],
1072bf215546Sopenharmony_ci                                         &pPipelines[i]);
1073bf215546Sopenharmony_ci      if (r != VK_SUCCESS) {
1074bf215546Sopenharmony_ci         result = r;
1075bf215546Sopenharmony_ci         pPipelines[i] = VK_NULL_HANDLE;
1076bf215546Sopenharmony_ci         if (pCreateInfos[i].flags & VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT)
1077bf215546Sopenharmony_ci            break;
1078bf215546Sopenharmony_ci      }
1079bf215546Sopenharmony_ci   }
1080bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
1081bf215546Sopenharmony_ci      for (; i < count; i++)
1082bf215546Sopenharmony_ci         pPipelines[i] = VK_NULL_HANDLE;
1083bf215546Sopenharmony_ci   }
1084bf215546Sopenharmony_ci
1085bf215546Sopenharmony_ci
1086bf215546Sopenharmony_ci   return result;
1087bf215546Sopenharmony_ci}
1088