+static uint32_t si_vgt_gs_mode(struct radv_shader_variant *gs)
+{
+ unsigned gs_max_vert_out = gs->info.gs.vertices_out;
+ unsigned cut_mode;
+
+ if (gs_max_vert_out <= 128) {
+ cut_mode = V_028A40_GS_CUT_128;
+ } else if (gs_max_vert_out <= 256) {
+ cut_mode = V_028A40_GS_CUT_256;
+ } else if (gs_max_vert_out <= 512) {
+ cut_mode = V_028A40_GS_CUT_512;
+ } else {
+ assert(gs_max_vert_out <= 1024);
+ cut_mode = V_028A40_GS_CUT_1024;
+ }
+
+ return S_028A40_MODE(V_028A40_GS_SCENARIO_G) |
+ S_028A40_CUT_MODE(cut_mode)|
+ S_028A40_ES_WRITE_OPTIMIZE(1) |
+ S_028A40_GS_WRITE_OPTIMIZE(1);
+}
+
+static void calculate_vgt_gs_mode(struct radv_pipeline *pipeline)
+{
+ struct radv_shader_variant *vs;
+ vs = radv_pipeline_has_gs(pipeline) ? pipeline->gs_copy_shader : (radv_pipeline_has_tess(pipeline) ? pipeline->shaders[MESA_SHADER_TESS_EVAL] : pipeline->shaders[MESA_SHADER_VERTEX]);
+
+ struct ac_vs_output_info *outinfo = &vs->info.vs.outinfo;
+
+ pipeline->graphics.vgt_primitiveid_en = false;
+ pipeline->graphics.vgt_gs_mode = 0;
+
+ if (radv_pipeline_has_gs(pipeline)) {
+ pipeline->graphics.vgt_gs_mode = si_vgt_gs_mode(pipeline->shaders[MESA_SHADER_GEOMETRY]);
+ } else if (outinfo->export_prim_id) {
+ pipeline->graphics.vgt_gs_mode = S_028A40_MODE(V_028A40_GS_SCENARIO_A);
+ pipeline->graphics.vgt_primitiveid_en = true;
+ }
+}
+
+static void calculate_pa_cl_vs_out_cntl(struct radv_pipeline *pipeline)
+{
+ struct radv_shader_variant *vs;
+ vs = radv_pipeline_has_gs(pipeline) ? pipeline->gs_copy_shader : (radv_pipeline_has_tess(pipeline) ? pipeline->shaders[MESA_SHADER_TESS_EVAL] : pipeline->shaders[MESA_SHADER_VERTEX]);
+
+ struct ac_vs_output_info *outinfo = &vs->info.vs.outinfo;
+
+ unsigned clip_dist_mask, cull_dist_mask, total_mask;
+ clip_dist_mask = outinfo->clip_dist_mask;
+ cull_dist_mask = outinfo->cull_dist_mask;
+ total_mask = clip_dist_mask | cull_dist_mask;
+
+ bool misc_vec_ena = outinfo->writes_pointsize ||
+ outinfo->writes_layer ||
+ outinfo->writes_viewport_index;
+ pipeline->graphics.pa_cl_vs_out_cntl =
+ S_02881C_USE_VTX_POINT_SIZE(outinfo->writes_pointsize) |
+ S_02881C_USE_VTX_RENDER_TARGET_INDX(outinfo->writes_layer) |
+ S_02881C_USE_VTX_VIEWPORT_INDX(outinfo->writes_viewport_index) |
+ S_02881C_VS_OUT_MISC_VEC_ENA(misc_vec_ena) |
+ S_02881C_VS_OUT_MISC_SIDE_BUS_ENA(misc_vec_ena) |
+ S_02881C_VS_OUT_CCDIST0_VEC_ENA((total_mask & 0x0f) != 0) |
+ S_02881C_VS_OUT_CCDIST1_VEC_ENA((total_mask & 0xf0) != 0) |
+ cull_dist_mask << 8 |
+ clip_dist_mask;
+
+}
+
+static uint32_t offset_to_ps_input(uint32_t offset, bool flat_shade)
+{
+ uint32_t ps_input_cntl;
+ if (offset <= AC_EXP_PARAM_OFFSET_31) {
+ ps_input_cntl = S_028644_OFFSET(offset);
+ if (flat_shade)
+ ps_input_cntl |= S_028644_FLAT_SHADE(1);
+ } else {
+ /* The input is a DEFAULT_VAL constant. */
+ assert(offset >= AC_EXP_PARAM_DEFAULT_VAL_0000 &&
+ offset <= AC_EXP_PARAM_DEFAULT_VAL_1111);
+ offset -= AC_EXP_PARAM_DEFAULT_VAL_0000;
+ ps_input_cntl = S_028644_OFFSET(0x20) |
+ S_028644_DEFAULT_VAL(offset);
+ }
+ return ps_input_cntl;
+}
+
+static void calculate_ps_inputs(struct radv_pipeline *pipeline)
+{
+ struct radv_shader_variant *ps, *vs;
+ struct ac_vs_output_info *outinfo;
+
+ ps = pipeline->shaders[MESA_SHADER_FRAGMENT];
+ vs = radv_pipeline_has_gs(pipeline) ? pipeline->gs_copy_shader : (radv_pipeline_has_tess(pipeline) ? pipeline->shaders[MESA_SHADER_TESS_EVAL] : pipeline->shaders[MESA_SHADER_VERTEX]);
+
+ outinfo = &vs->info.vs.outinfo;
+
+ unsigned ps_offset = 0;
+
+ if (ps->info.fs.prim_id_input) {
+ unsigned vs_offset = outinfo->vs_output_param_offset[VARYING_SLOT_PRIMITIVE_ID];
+ if (vs_offset != AC_EXP_PARAM_UNDEFINED) {
+ pipeline->graphics.ps_input_cntl[ps_offset] = offset_to_ps_input(vs_offset, true);
+ ++ps_offset;
+ }
+ }
+
+ if (ps->info.fs.layer_input) {
+ unsigned vs_offset = outinfo->vs_output_param_offset[VARYING_SLOT_LAYER];
+ if (vs_offset != AC_EXP_PARAM_UNDEFINED)
+ pipeline->graphics.ps_input_cntl[ps_offset] = offset_to_ps_input(vs_offset, true);
+ else
+ pipeline->graphics.ps_input_cntl[ps_offset] = offset_to_ps_input(AC_EXP_PARAM_DEFAULT_VAL_0000, true);
+ ++ps_offset;
+ }
+
+ if (ps->info.fs.has_pcoord) {
+ unsigned val;
+ val = S_028644_PT_SPRITE_TEX(1) | S_028644_OFFSET(0x20);
+ pipeline->graphics.ps_input_cntl[ps_offset] = val;
+ ps_offset++;
+ }
+
+ for (unsigned i = 0; i < 32 && (1u << i) <= ps->info.fs.input_mask; ++i) {
+ unsigned vs_offset;
+ bool flat_shade;
+ if (!(ps->info.fs.input_mask & (1u << i)))
+ continue;
+
+ vs_offset = outinfo->vs_output_param_offset[VARYING_SLOT_VAR0 + i];
+ if (vs_offset == AC_EXP_PARAM_UNDEFINED) {
+ pipeline->graphics.ps_input_cntl[ps_offset] = S_028644_OFFSET(0x20);
+ ++ps_offset;
+ continue;
+ }
+
+ flat_shade = !!(ps->info.fs.flat_shaded_mask & (1u << ps_offset));
+
+ pipeline->graphics.ps_input_cntl[ps_offset] = offset_to_ps_input(vs_offset, flat_shade);
+ ++ps_offset;
+ }
+
+ pipeline->graphics.ps_input_cntl_num = ps_offset;
+}
+
+static void
+radv_link_shaders(struct radv_pipeline *pipeline, nir_shader **shaders)
+{
+ nir_shader* ordered_shaders[MESA_SHADER_STAGES];
+ int shader_count = 0;
+
+ if(shaders[MESA_SHADER_FRAGMENT]) {
+ ordered_shaders[shader_count++] = shaders[MESA_SHADER_FRAGMENT];
+ }
+ if(shaders[MESA_SHADER_GEOMETRY]) {
+ ordered_shaders[shader_count++] = shaders[MESA_SHADER_GEOMETRY];
+ }
+ if(shaders[MESA_SHADER_TESS_EVAL]) {
+ ordered_shaders[shader_count++] = shaders[MESA_SHADER_TESS_EVAL];
+ }
+ if(shaders[MESA_SHADER_TESS_CTRL]) {
+ ordered_shaders[shader_count++] = shaders[MESA_SHADER_TESS_CTRL];
+ }
+ if(shaders[MESA_SHADER_VERTEX]) {
+ ordered_shaders[shader_count++] = shaders[MESA_SHADER_VERTEX];
+ }
+
+ for (int i = 1; i < shader_count; ++i) {
+ nir_remove_dead_variables(ordered_shaders[i],
+ nir_var_shader_out);
+ nir_remove_dead_variables(ordered_shaders[i - 1],
+ nir_var_shader_in);
+
+ bool progress = nir_remove_unused_varyings(ordered_shaders[i],
+ ordered_shaders[i - 1]);
+
+ if (progress) {
+ nir_lower_global_vars_to_local(ordered_shaders[i]);
+ radv_optimize_nir(ordered_shaders[i]);
+ nir_lower_global_vars_to_local(ordered_shaders[i - 1]);
+ radv_optimize_nir(ordered_shaders[i - 1]);
+ }
+ }
+}
+
+static
+void radv_create_shaders(struct radv_pipeline *pipeline,
+ struct radv_device *device,
+ struct radv_pipeline_cache *cache,
+ struct ac_shader_variant_key *keys,
+ const VkPipelineShaderStageCreateInfo **pStages)
+{
+ struct radv_shader_module fs_m = {0};
+ struct radv_shader_module *modules[MESA_SHADER_STAGES] = { 0, };
+ nir_shader *nir[MESA_SHADER_STAGES] = {0};
+ void *codes[MESA_SHADER_STAGES] = {0};
+ unsigned code_sizes[MESA_SHADER_STAGES] = {0};
+ unsigned char hash[20], gs_copy_hash[20];
+
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) {
+ if (pStages[i]) {
+ modules[i] = radv_shader_module_from_handle(pStages[i]->module);
+ if (modules[i]->nir)
+ _mesa_sha1_compute(modules[i]->nir->info.name,
+ strlen(modules[i]->nir->info.name),
+ modules[i]->sha1);
+ }
+ }
+
+ radv_hash_shaders(hash, pStages, pipeline->layout, keys, get_hash_flags(device));
+ memcpy(gs_copy_hash, hash, 20);
+ gs_copy_hash[0] ^= 1;
+
+ if (modules[MESA_SHADER_GEOMETRY]) {
+ struct radv_shader_variant *variants[MESA_SHADER_STAGES] = {0};
+ radv_create_shader_variants_from_pipeline_cache(device, cache, gs_copy_hash, variants);
+ pipeline->gs_copy_shader = variants[MESA_SHADER_GEOMETRY];
+ }
+
+ if (radv_create_shader_variants_from_pipeline_cache(device, cache, hash, pipeline->shaders) &&
+ (!modules[MESA_SHADER_GEOMETRY] || pipeline->gs_copy_shader)) {
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) {
+ if (pipeline->shaders[i])
+ pipeline->active_stages |= mesa_to_vk_shader_stage(i);
+ }
+ return;
+ }
+
+ if (!modules[MESA_SHADER_FRAGMENT] && !modules[MESA_SHADER_COMPUTE]) {
+ nir_builder fs_b;
+ nir_builder_init_simple_shader(&fs_b, NULL, MESA_SHADER_FRAGMENT, NULL);
+ fs_b.shader->info.name = ralloc_strdup(fs_b.shader, "noop_fs");
+ fs_m.nir = fs_b.shader;
+ modules[MESA_SHADER_FRAGMENT] = &fs_m;
+ }
+
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) {
+ const VkPipelineShaderStageCreateInfo *stage = pStages[i];
+
+ if (!modules[i])
+ continue;
+
+ nir[i] = radv_shader_compile_to_nir(device, modules[i],
+ stage ? stage->pName : "main", i,
+ stage ? stage->pSpecializationInfo : NULL);
+ pipeline->active_stages |= mesa_to_vk_shader_stage(i);
+ }
+
+ if (nir[MESA_SHADER_TESS_CTRL]) {
+ /* TODO: This is no longer used as a key we should refactor this */
+ if (keys)
+ keys[MESA_SHADER_TESS_CTRL].tcs.primitive_mode = nir[MESA_SHADER_TESS_EVAL]->info.tess.primitive_mode;
+
+ nir_lower_tes_patch_vertices(nir[MESA_SHADER_TESS_EVAL], nir[MESA_SHADER_TESS_CTRL]->info.tess.tcs_vertices_out);
+ }
+
+ radv_link_shaders(pipeline, nir);
+
+ if (nir[MESA_SHADER_FRAGMENT]) {
+ pipeline->shaders[MESA_SHADER_FRAGMENT] =
+ radv_shader_variant_create(device, modules[MESA_SHADER_FRAGMENT], &nir[MESA_SHADER_FRAGMENT], 1,
+ pipeline->layout, keys ? keys + MESA_SHADER_FRAGMENT : 0,
+ &codes[MESA_SHADER_FRAGMENT], &code_sizes[MESA_SHADER_FRAGMENT]);
+
+ /* TODO: These are no longer used as keys we should refactor this */
+ if (keys) {
+ keys[MESA_SHADER_VERTEX].vs.export_prim_id =
+ pipeline->shaders[MESA_SHADER_FRAGMENT]->info.fs.prim_id_input;
+ keys[MESA_SHADER_TESS_EVAL].tes.export_prim_id =
+ pipeline->shaders[MESA_SHADER_FRAGMENT]->info.fs.prim_id_input;
+ }
+
+ pipeline->active_stages |= mesa_to_vk_shader_stage(MESA_SHADER_FRAGMENT);
+ }
+
+ if (device->physical_device->rad_info.chip_class >= GFX9 &&
+ modules[MESA_SHADER_TESS_CTRL] && !pipeline->shaders[MESA_SHADER_TESS_CTRL]) {
+ struct nir_shader *combined_nir[] = {nir[MESA_SHADER_VERTEX], nir[MESA_SHADER_TESS_CTRL]};
+ struct ac_shader_variant_key key = keys[MESA_SHADER_TESS_CTRL];
+ key.tcs.vs_key = keys[MESA_SHADER_VERTEX].vs;
+ pipeline->shaders[MESA_SHADER_TESS_CTRL] = radv_shader_variant_create(device, modules[MESA_SHADER_TESS_CTRL], combined_nir, 2,
+ pipeline->layout,
+ &key, &codes[MESA_SHADER_TESS_CTRL],
+ &code_sizes[MESA_SHADER_TESS_CTRL]);
+ modules[MESA_SHADER_VERTEX] = NULL;
+ }
+
+ if (device->physical_device->rad_info.chip_class >= GFX9 &&
+ modules[MESA_SHADER_GEOMETRY] && !pipeline->shaders[MESA_SHADER_GEOMETRY]) {
+ gl_shader_stage pre_stage = modules[MESA_SHADER_TESS_EVAL] ? MESA_SHADER_TESS_EVAL : MESA_SHADER_VERTEX;
+ struct nir_shader *combined_nir[] = {nir[pre_stage], nir[MESA_SHADER_GEOMETRY]};
+ pipeline->shaders[MESA_SHADER_GEOMETRY] = radv_shader_variant_create(device, modules[MESA_SHADER_GEOMETRY], combined_nir, 2,
+ pipeline->layout,
+ &keys[pre_stage] , &codes[MESA_SHADER_GEOMETRY],
+ &code_sizes[MESA_SHADER_GEOMETRY]);
+ modules[pre_stage] = NULL;
+ }
+
+ for (int i = 0; i < MESA_SHADER_STAGES; ++i) {
+ if(modules[i] && !pipeline->shaders[i]) {
+ pipeline->shaders[i] = radv_shader_variant_create(device, modules[i], &nir[i], 1,
+ pipeline->layout,
+ keys ? keys + i : 0, &codes[i],
+ &code_sizes[i]);
+ }
+ }
+
+ if(modules[MESA_SHADER_GEOMETRY]) {
+ void *gs_copy_code = NULL;
+ unsigned gs_copy_code_size = 0;
+ if (!pipeline->gs_copy_shader) {
+ pipeline->gs_copy_shader = radv_create_gs_copy_shader(
+ device, nir[MESA_SHADER_GEOMETRY], &gs_copy_code,
+ &gs_copy_code_size,
+ keys[MESA_SHADER_GEOMETRY].has_multiview_view_index);
+ }
+
+ if (pipeline->gs_copy_shader) {
+ void *code[MESA_SHADER_STAGES] = {0};
+ unsigned code_size[MESA_SHADER_STAGES] = {0};
+ struct radv_shader_variant *variants[MESA_SHADER_STAGES] = {0};
+
+ code[MESA_SHADER_GEOMETRY] = gs_copy_code;
+ code_size[MESA_SHADER_GEOMETRY] = gs_copy_code_size;
+ variants[MESA_SHADER_GEOMETRY] = pipeline->gs_copy_shader;
+
+ radv_pipeline_cache_insert_shaders(device, cache,
+ gs_copy_hash,
+ variants,
+ (const void**)code,
+ code_size);
+ }
+ free(gs_copy_code);
+ }
+
+ radv_pipeline_cache_insert_shaders(device, cache, hash, pipeline->shaders,
+ (const void**)codes, code_sizes);
+
+ for (int i = 0; i < MESA_SHADER_STAGES; ++i) {
+ free(codes[i]);
+ if (modules[i] && !modules[i]->nir && !pipeline->device->trace_bo)
+ ralloc_free(nir[i]);
+ }
+
+ if (fs_m.nir)
+ ralloc_free(fs_m.nir);
+}
+
+static VkResult