+enum {
+ DEPTH_RESOLVE,
+ STENCIL_RESOLVE,
+};
+
+static const char *
+get_resolve_mode_str(VkResolveModeFlagBits resolve_mode)
+{
+ switch (resolve_mode) {
+ case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR:
+ return "zero";
+ case VK_RESOLVE_MODE_AVERAGE_BIT_KHR:
+ return "average";
+ case VK_RESOLVE_MODE_MIN_BIT_KHR:
+ return "min";
+ case VK_RESOLVE_MODE_MAX_BIT_KHR:
+ return "max";
+ default:
+ unreachable("invalid resolve mode");
+ }
+}
+
+static nir_shader *
+build_depth_stencil_resolve_compute_shader(struct radv_device *dev, int samples,
+ int index,
+ VkResolveModeFlagBits resolve_mode)
+{
+ nir_builder b;
+ char name[64];
+ const struct glsl_type *sampler_type = glsl_sampler_type(GLSL_SAMPLER_DIM_MS,
+ false,
+ false,
+ GLSL_TYPE_FLOAT);
+ const struct glsl_type *img_type = glsl_sampler_type(GLSL_SAMPLER_DIM_2D,
+ false,
+ false,
+ GLSL_TYPE_FLOAT);
+ snprintf(name, 64, "meta_resolve_cs_%s-%s-%d",
+ index == DEPTH_RESOLVE ? "depth" : "stencil",
+ get_resolve_mode_str(resolve_mode), samples);
+
+ nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_COMPUTE, NULL);
+ b.shader->info.name = ralloc_strdup(b.shader, name);
+ b.shader->info.cs.local_size[0] = 16;
+ b.shader->info.cs.local_size[1] = 16;
+ b.shader->info.cs.local_size[2] = 1;
+
+ nir_variable *input_img = nir_variable_create(b.shader, nir_var_uniform,
+ sampler_type, "s_tex");
+ input_img->data.descriptor_set = 0;
+ input_img->data.binding = 0;
+
+ nir_variable *output_img = nir_variable_create(b.shader, nir_var_uniform,
+ img_type, "out_img");
+ output_img->data.descriptor_set = 0;
+ output_img->data.binding = 1;
+ nir_ssa_def *invoc_id = nir_load_local_invocation_id(&b);
+ nir_ssa_def *wg_id = nir_load_work_group_id(&b);
+ nir_ssa_def *block_size = nir_imm_ivec4(&b,
+ b.shader->info.cs.local_size[0],
+ b.shader->info.cs.local_size[1],
+ b.shader->info.cs.local_size[2], 0);
+
+ nir_ssa_def *global_id = nir_iadd(&b, nir_imul(&b, wg_id, block_size), invoc_id);
+
+ nir_intrinsic_instr *src_offset = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_push_constant);
+ nir_intrinsic_set_base(src_offset, 0);
+ nir_intrinsic_set_range(src_offset, 16);
+ src_offset->src[0] = nir_src_for_ssa(nir_imm_int(&b, 0));
+ src_offset->num_components = 2;
+ nir_ssa_dest_init(&src_offset->instr, &src_offset->dest, 2, 32, "src_offset");
+ nir_builder_instr_insert(&b, &src_offset->instr);
+
+ nir_intrinsic_instr *dst_offset = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_push_constant);
+ nir_intrinsic_set_base(dst_offset, 0);
+ nir_intrinsic_set_range(dst_offset, 16);
+ dst_offset->src[0] = nir_src_for_ssa(nir_imm_int(&b, 8));
+ dst_offset->num_components = 2;
+ nir_ssa_dest_init(&dst_offset->instr, &dst_offset->dest, 2, 32, "dst_offset");
+ nir_builder_instr_insert(&b, &dst_offset->instr);
+
+ nir_ssa_def *img_coord = nir_channels(&b, nir_iadd(&b, global_id, &src_offset->dest.ssa), 0x3);
+
+ nir_ssa_def *input_img_deref = &nir_build_deref_var(&b, input_img)->dest.ssa;
+
+ nir_alu_type type = index == DEPTH_RESOLVE ? nir_type_float : nir_type_uint;
+
+ nir_tex_instr *tex = nir_tex_instr_create(b.shader, 3);
+ tex->sampler_dim = GLSL_SAMPLER_DIM_MS;
+ tex->op = nir_texop_txf_ms;
+ tex->src[0].src_type = nir_tex_src_coord;
+ tex->src[0].src = nir_src_for_ssa(img_coord);
+ tex->src[1].src_type = nir_tex_src_ms_index;
+ tex->src[1].src = nir_src_for_ssa(nir_imm_int(&b, 0));
+ tex->src[2].src_type = nir_tex_src_texture_deref;
+ tex->src[2].src = nir_src_for_ssa(input_img_deref);
+ tex->dest_type = type;
+ tex->is_array = false;
+ tex->coord_components = 2;
+
+ nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, "tex");
+ nir_builder_instr_insert(&b, &tex->instr);
+
+ nir_ssa_def *outval = &tex->dest.ssa;
+
+ if (resolve_mode != VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) {
+ for (int i = 1; i < samples; i++) {
+ nir_tex_instr *tex_add = nir_tex_instr_create(b.shader, 3);
+ tex_add->sampler_dim = GLSL_SAMPLER_DIM_MS;
+ tex_add->op = nir_texop_txf_ms;
+ tex_add->src[0].src_type = nir_tex_src_coord;
+ tex_add->src[0].src = nir_src_for_ssa(img_coord);
+ tex_add->src[1].src_type = nir_tex_src_ms_index;
+ tex_add->src[1].src = nir_src_for_ssa(nir_imm_int(&b, i));
+ tex_add->src[2].src_type = nir_tex_src_texture_deref;
+ tex_add->src[2].src = nir_src_for_ssa(input_img_deref);
+ tex_add->dest_type = type;
+ tex_add->is_array = false;
+ tex_add->coord_components = 2;
+
+ nir_ssa_dest_init(&tex_add->instr, &tex_add->dest, 4, 32, "tex");
+ nir_builder_instr_insert(&b, &tex_add->instr);
+
+ switch (resolve_mode) {
+ case VK_RESOLVE_MODE_AVERAGE_BIT_KHR:
+ assert(index == DEPTH_RESOLVE);
+ outval = nir_fadd(&b, outval, &tex_add->dest.ssa);
+ break;
+ case VK_RESOLVE_MODE_MIN_BIT_KHR:
+ if (index == DEPTH_RESOLVE)
+ outval = nir_fmin(&b, outval, &tex_add->dest.ssa);
+ else
+ outval = nir_umin(&b, outval, &tex_add->dest.ssa);
+ break;
+ case VK_RESOLVE_MODE_MAX_BIT_KHR:
+ if (index == DEPTH_RESOLVE)
+ outval = nir_fmax(&b, outval, &tex_add->dest.ssa);
+ else
+ outval = nir_umax(&b, outval, &tex_add->dest.ssa);
+ break;
+ default:
+ unreachable("invalid resolve mode");
+ }
+ }
+
+ if (resolve_mode == VK_RESOLVE_MODE_AVERAGE_BIT_KHR)
+ outval = nir_fdiv(&b, outval, nir_imm_float(&b, samples));
+ }
+
+ nir_ssa_def *coord = nir_iadd(&b, global_id, &dst_offset->dest.ssa);
+ nir_intrinsic_instr *store = nir_intrinsic_instr_create(b.shader, nir_intrinsic_image_deref_store);
+ store->num_components = 4;
+ store->src[0] = nir_src_for_ssa(&nir_build_deref_var(&b, output_img)->dest.ssa);
+ store->src[1] = nir_src_for_ssa(coord);
+ store->src[2] = nir_src_for_ssa(nir_ssa_undef(&b, 1, 32));
+ store->src[3] = nir_src_for_ssa(outval);
+ store->src[4] = nir_src_for_ssa(nir_imm_int(&b, 0));
+ nir_builder_instr_insert(&b, &store->instr);
+ return b.shader;
+}