+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_fragment_shader(struct radv_device *dev, int samples,
+ int index,
+ VkResolveModeFlagBits resolve_mode)
+{
+ nir_builder b;
+ char name[64];
+ const struct glsl_type *vec4 = glsl_vec4_type();
+ const struct glsl_type *sampler_type = glsl_sampler_type(GLSL_SAMPLER_DIM_2D,
+ false,
+ false,
+ GLSL_TYPE_FLOAT);
+
+ snprintf(name, 64, "meta_resolve_fs_%s-%s-%d",
+ index == DEPTH_RESOLVE ? "depth" : "stencil",
+ get_resolve_mode_str(resolve_mode), samples);
+
+ nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
+ b.shader->info.name = ralloc_strdup(b.shader, name);
+
+ 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 *fs_out = nir_variable_create(b.shader,
+ nir_var_shader_out, vec4,
+ "f_out");
+ fs_out->data.location =
+ index == DEPTH_RESOLVE ? FRAG_RESULT_DEPTH : FRAG_RESULT_STENCIL;
+
+ nir_ssa_def *pos_in = nir_channels(&b, nir_load_frag_coord(&b), 0x3);
+
+ 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, 8);
+ 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_ssa_def *pos_int = nir_f2i32(&b, pos_in);
+
+ nir_ssa_def *img_coord = nir_channels(&b, nir_iadd(&b, pos_int, &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_store_var(&b, fs_out, outval, 0x1);
+
+ return b.shader;
+}
+
+static VkResult
+create_depth_stencil_resolve_pipeline(struct radv_device *device,
+ int samples_log2,
+ int index,
+ VkResolveModeFlagBits resolve_mode)
+{
+ VkRenderPass *render_pass;
+ VkPipeline *pipeline;
+ VkFormat src_format;
+ VkResult result;
+
+ mtx_lock(&device->meta_state.mtx);
+
+ switch (resolve_mode) {
+ case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR:
+ if (index == DEPTH_RESOLVE)
+ pipeline = &device->meta_state.resolve_fragment.depth_zero_pipeline;
+ else
+ pipeline = &device->meta_state.resolve_fragment.stencil_zero_pipeline;
+ break;
+ case VK_RESOLVE_MODE_AVERAGE_BIT_KHR:
+ assert(index == DEPTH_RESOLVE);
+ pipeline = &device->meta_state.resolve_fragment.depth[samples_log2].average_pipeline;
+ break;
+ case VK_RESOLVE_MODE_MIN_BIT_KHR:
+ if (index == DEPTH_RESOLVE)
+ pipeline = &device->meta_state.resolve_fragment.depth[samples_log2].min_pipeline;
+ else
+ pipeline = &device->meta_state.resolve_fragment.stencil[samples_log2].min_pipeline;
+ break;
+ case VK_RESOLVE_MODE_MAX_BIT_KHR:
+ if (index == DEPTH_RESOLVE)
+ pipeline = &device->meta_state.resolve_fragment.depth[samples_log2].max_pipeline;
+ else
+ pipeline = &device->meta_state.resolve_fragment.stencil[samples_log2].max_pipeline;
+ break;
+ default:
+ unreachable("invalid resolve mode");
+ }
+
+ if (*pipeline) {
+ mtx_unlock(&device->meta_state.mtx);
+ return VK_SUCCESS;
+ }
+
+ struct radv_shader_module fs = { .nir = NULL };
+ struct radv_shader_module vs = { .nir = NULL };
+ uint32_t samples = 1 << samples_log2;
+
+ vs.nir = build_nir_vertex_shader();
+ fs.nir = build_depth_stencil_resolve_fragment_shader(device, samples,
+ index, resolve_mode);
+
+ VkPipelineShaderStageCreateInfo pipeline_shader_stages[] = {
+ {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_VERTEX_BIT,
+ .module = radv_shader_module_to_handle(&vs),
+ .pName = "main",
+ .pSpecializationInfo = NULL
+ }, {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
+ .module = radv_shader_module_to_handle(&fs),
+ .pName = "main",
+ .pSpecializationInfo = NULL
+ },
+ };
+
+ if (index == DEPTH_RESOLVE) {
+ src_format = VK_FORMAT_D32_SFLOAT;
+ render_pass = &device->meta_state.resolve_fragment.depth_render_pass;
+ } else {
+ render_pass = &device->meta_state.resolve_fragment.stencil_render_pass;
+ src_format = VK_FORMAT_S8_UINT;
+ }
+
+ if (!*render_pass) {
+ result = radv_CreateRenderPass(radv_device_to_handle(device),
+ &(VkRenderPassCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+ .attachmentCount = 1,
+ .pAttachments = &(VkAttachmentDescription) {
+ .format = src_format,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
+ .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
+ .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
+ .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
+ },
+ .subpassCount = 1,
+ .pSubpasses = &(VkSubpassDescription) {
+ .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+ .inputAttachmentCount = 0,
+ .colorAttachmentCount = 0,
+ .pColorAttachments = NULL,
+ .pResolveAttachments = NULL,
+ .pDepthStencilAttachment = &(VkAttachmentReference) {
+ .attachment = 0,
+ .layout = VK_IMAGE_LAYOUT_GENERAL,
+ },
+ .preserveAttachmentCount = 0,
+ .pPreserveAttachments = NULL,
+ },
+ .dependencyCount = 2,
+ .pDependencies = (VkSubpassDependency[]) {
+ {
+ .srcSubpass = VK_SUBPASS_EXTERNAL,
+ .dstSubpass = 0,
+ .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+ .srcAccessMask = 0,
+ .dstAccessMask = 0,
+ .dependencyFlags = 0
+ },
+ {
+ .srcSubpass = 0,
+ .dstSubpass = VK_SUBPASS_EXTERNAL,
+ .srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+ .srcAccessMask = 0,
+ .dstAccessMask = 0,
+ .dependencyFlags = 0
+ }
+ },
+ }, &device->meta_state.alloc, render_pass);
+ }
+
+ VkStencilOp stencil_op =
+ index == DEPTH_RESOLVE ? VK_STENCIL_OP_KEEP : VK_STENCIL_OP_REPLACE;
+
+ VkPipelineDepthStencilStateCreateInfo depth_stencil_state = {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+ .depthTestEnable = true,
+ .depthWriteEnable = index == DEPTH_RESOLVE,
+ .stencilTestEnable = index == STENCIL_RESOLVE,
+ .depthCompareOp = VK_COMPARE_OP_ALWAYS,
+ .front = {
+ .failOp = stencil_op,
+ .passOp = stencil_op,
+ .depthFailOp = stencil_op,
+ .compareOp = VK_COMPARE_OP_ALWAYS,
+ },
+ .back = {
+ .failOp = stencil_op,
+ .passOp = stencil_op,
+ .depthFailOp = stencil_op,
+ .compareOp = VK_COMPARE_OP_ALWAYS,
+ }
+ };
+
+ const VkPipelineVertexInputStateCreateInfo *vi_create_info;
+ vi_create_info = &normal_vi_create_info;
+
+ const VkGraphicsPipelineCreateInfo vk_pipeline_info = {
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .stageCount = ARRAY_SIZE(pipeline_shader_stages),
+ .pStages = pipeline_shader_stages,
+ .pVertexInputState = vi_create_info,
+ .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+ .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ .primitiveRestartEnable = false,
+ },
+ .pViewportState = &(VkPipelineViewportStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+ .viewportCount = 1,
+ .scissorCount = 1,
+ },
+ .pDepthStencilState = &depth_stencil_state,
+ .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+ .rasterizerDiscardEnable = false,
+ .polygonMode = VK_POLYGON_MODE_FILL,
+ .cullMode = VK_CULL_MODE_NONE,
+ .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE
+ },
+ .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+ .rasterizationSamples = 1,
+ .sampleShadingEnable = false,
+ .pSampleMask = (VkSampleMask[]) { UINT32_MAX },
+ },
+ .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+ .attachmentCount = 0,
+ .pAttachments = (VkPipelineColorBlendAttachmentState []) {
+ { .colorWriteMask =
+ VK_COLOR_COMPONENT_A_BIT |
+ VK_COLOR_COMPONENT_R_BIT |
+ VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT },
+ }
+ },
+ .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+ .dynamicStateCount = 9,
+ .pDynamicStates = (VkDynamicState[]) {
+ VK_DYNAMIC_STATE_VIEWPORT,
+ VK_DYNAMIC_STATE_SCISSOR,
+ VK_DYNAMIC_STATE_LINE_WIDTH,
+ VK_DYNAMIC_STATE_DEPTH_BIAS,
+ VK_DYNAMIC_STATE_BLEND_CONSTANTS,
+ VK_DYNAMIC_STATE_DEPTH_BOUNDS,
+ VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
+ VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
+ VK_DYNAMIC_STATE_STENCIL_REFERENCE,
+ },
+ },
+ .flags = 0,
+ .layout = device->meta_state.resolve_fragment.p_layout,
+ .renderPass = *render_pass,
+ .subpass = 0,
+ };
+
+ const struct radv_graphics_pipeline_create_info radv_pipeline_info = {
+ .use_rectlist = true
+ };
+
+ result = radv_graphics_pipeline_create(radv_device_to_handle(device),
+ radv_pipeline_cache_to_handle(&device->meta_state.cache),
+ &vk_pipeline_info, &radv_pipeline_info,
+ &device->meta_state.alloc,
+ pipeline);
+
+ ralloc_free(vs.nir);
+ ralloc_free(fs.nir);
+
+ mtx_unlock(&device->meta_state.mtx);
+ return result;
+}
+