17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2020 Raspberry Pi
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg#include "v3dv_private.h"
257ec681f3Smrg#include "v3dv_meta_common.h"
267ec681f3Smrg
277ec681f3Smrg#include "compiler/nir/nir_builder.h"
287ec681f3Smrg#include "vk_format_info.h"
297ec681f3Smrg#include "util/u_pack_color.h"
307ec681f3Smrg
317ec681f3Smrgstatic void
327ec681f3Smrgget_hw_clear_color(struct v3dv_device *device,
337ec681f3Smrg                   const VkClearColorValue *color,
347ec681f3Smrg                   VkFormat fb_format,
357ec681f3Smrg                   VkFormat image_format,
367ec681f3Smrg                   uint32_t internal_type,
377ec681f3Smrg                   uint32_t internal_bpp,
387ec681f3Smrg                   uint32_t *hw_color)
397ec681f3Smrg{
407ec681f3Smrg   const uint32_t internal_size = 4 << internal_bpp;
417ec681f3Smrg
427ec681f3Smrg   /* If the image format doesn't match the framebuffer format, then we are
437ec681f3Smrg    * trying to clear an unsupported tlb format using a compatible
447ec681f3Smrg    * format for the framebuffer. In this case, we want to make sure that
457ec681f3Smrg    * we pack the clear value according to the original format semantics,
467ec681f3Smrg    * not the compatible format.
477ec681f3Smrg    */
487ec681f3Smrg   if (fb_format == image_format) {
497ec681f3Smrg      v3dv_X(device, get_hw_clear_color)(color, internal_type, internal_size,
507ec681f3Smrg                                         hw_color);
517ec681f3Smrg   } else {
527ec681f3Smrg      union util_color uc;
537ec681f3Smrg      enum pipe_format pipe_image_format =
547ec681f3Smrg         vk_format_to_pipe_format(image_format);
557ec681f3Smrg      util_pack_color(color->float32, pipe_image_format, &uc);
567ec681f3Smrg      memcpy(hw_color, uc.ui, internal_size);
577ec681f3Smrg   }
587ec681f3Smrg}
597ec681f3Smrg
607ec681f3Smrg/* Returns true if the implementation is able to handle the case, false
617ec681f3Smrg * otherwise.
627ec681f3Smrg*/
637ec681f3Smrgstatic bool
647ec681f3Smrgclear_image_tlb(struct v3dv_cmd_buffer *cmd_buffer,
657ec681f3Smrg                struct v3dv_image *image,
667ec681f3Smrg                const VkClearValue *clear_value,
677ec681f3Smrg                const VkImageSubresourceRange *range)
687ec681f3Smrg{
697ec681f3Smrg   const VkOffset3D origin = { 0, 0, 0 };
707ec681f3Smrg   VkFormat fb_format;
717ec681f3Smrg   if (!v3dv_meta_can_use_tlb(image, &origin, &fb_format))
727ec681f3Smrg      return false;
737ec681f3Smrg
747ec681f3Smrg   uint32_t internal_type, internal_bpp;
757ec681f3Smrg   v3dv_X(cmd_buffer->device, get_internal_type_bpp_for_image_aspects)
767ec681f3Smrg      (fb_format, range->aspectMask,
777ec681f3Smrg       &internal_type, &internal_bpp);
787ec681f3Smrg
797ec681f3Smrg   union v3dv_clear_value hw_clear_value = { 0 };
807ec681f3Smrg   if (range->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
817ec681f3Smrg      get_hw_clear_color(cmd_buffer->device, &clear_value->color, fb_format,
827ec681f3Smrg                         image->vk.format, internal_type, internal_bpp,
837ec681f3Smrg                         &hw_clear_value.color[0]);
847ec681f3Smrg   } else {
857ec681f3Smrg      assert((range->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
867ec681f3Smrg             (range->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT));
877ec681f3Smrg      hw_clear_value.z = clear_value->depthStencil.depth;
887ec681f3Smrg      hw_clear_value.s = clear_value->depthStencil.stencil;
897ec681f3Smrg   }
907ec681f3Smrg
917ec681f3Smrg   uint32_t level_count = vk_image_subresource_level_count(&image->vk, range);
927ec681f3Smrg   uint32_t min_level = range->baseMipLevel;
937ec681f3Smrg   uint32_t max_level = range->baseMipLevel + level_count;
947ec681f3Smrg
957ec681f3Smrg   /* For 3D images baseArrayLayer and layerCount must be 0 and 1 respectively.
967ec681f3Smrg    * Instead, we need to consider the full depth dimension of the image, which
977ec681f3Smrg    * goes from 0 up to the level's depth extent.
987ec681f3Smrg    */
997ec681f3Smrg   uint32_t min_layer;
1007ec681f3Smrg   uint32_t max_layer;
1017ec681f3Smrg   if (image->vk.image_type != VK_IMAGE_TYPE_3D) {
1027ec681f3Smrg      min_layer = range->baseArrayLayer;
1037ec681f3Smrg      max_layer = range->baseArrayLayer +
1047ec681f3Smrg                  vk_image_subresource_layer_count(&image->vk, range);
1057ec681f3Smrg   } else {
1067ec681f3Smrg      min_layer = 0;
1077ec681f3Smrg      max_layer = 0;
1087ec681f3Smrg   }
1097ec681f3Smrg
1107ec681f3Smrg   for (uint32_t level = min_level; level < max_level; level++) {
1117ec681f3Smrg      if (image->vk.image_type == VK_IMAGE_TYPE_3D)
1127ec681f3Smrg         max_layer = u_minify(image->vk.extent.depth, level);
1137ec681f3Smrg
1147ec681f3Smrg      uint32_t width = u_minify(image->vk.extent.width, level);
1157ec681f3Smrg      uint32_t height = u_minify(image->vk.extent.height, level);
1167ec681f3Smrg
1177ec681f3Smrg      struct v3dv_job *job =
1187ec681f3Smrg         v3dv_cmd_buffer_start_job(cmd_buffer, -1, V3DV_JOB_TYPE_GPU_CL);
1197ec681f3Smrg
1207ec681f3Smrg      if (!job)
1217ec681f3Smrg         return true;
1227ec681f3Smrg
1237ec681f3Smrg      v3dv_job_start_frame(job, width, height, max_layer, false,
1247ec681f3Smrg                           1, internal_bpp,
1257ec681f3Smrg                           image->vk.samples > VK_SAMPLE_COUNT_1_BIT);
1267ec681f3Smrg
1277ec681f3Smrg      struct v3dv_meta_framebuffer framebuffer;
1287ec681f3Smrg      v3dv_X(job->device, meta_framebuffer_init)(&framebuffer, fb_format,
1297ec681f3Smrg                                                 internal_type,
1307ec681f3Smrg                                                 &job->frame_tiling);
1317ec681f3Smrg
1327ec681f3Smrg      v3dv_X(job->device, job_emit_binning_flush)(job);
1337ec681f3Smrg
1347ec681f3Smrg      /* If this triggers it is an application bug: the spec requires
1357ec681f3Smrg       * that any aspects to clear are present in the image.
1367ec681f3Smrg       */
1377ec681f3Smrg      assert(range->aspectMask & image->vk.aspects);
1387ec681f3Smrg
1397ec681f3Smrg      v3dv_X(job->device, meta_emit_clear_image_rcl)
1407ec681f3Smrg         (job, image, &framebuffer, &hw_clear_value,
1417ec681f3Smrg          range->aspectMask, min_layer, max_layer, level);
1427ec681f3Smrg
1437ec681f3Smrg      v3dv_cmd_buffer_finish_job(cmd_buffer);
1447ec681f3Smrg   }
1457ec681f3Smrg
1467ec681f3Smrg   return true;
1477ec681f3Smrg}
1487ec681f3Smrg
1497ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
1507ec681f3Smrgv3dv_CmdClearColorImage(VkCommandBuffer commandBuffer,
1517ec681f3Smrg                        VkImage _image,
1527ec681f3Smrg                        VkImageLayout imageLayout,
1537ec681f3Smrg                        const VkClearColorValue *pColor,
1547ec681f3Smrg                        uint32_t rangeCount,
1557ec681f3Smrg                        const VkImageSubresourceRange *pRanges)
1567ec681f3Smrg{
1577ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
1587ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_image, image, _image);
1597ec681f3Smrg
1607ec681f3Smrg   const VkClearValue clear_value = {
1617ec681f3Smrg      .color = *pColor,
1627ec681f3Smrg   };
1637ec681f3Smrg
1647ec681f3Smrg   for (uint32_t i = 0; i < rangeCount; i++) {
1657ec681f3Smrg      if (clear_image_tlb(cmd_buffer, image, &clear_value, &pRanges[i]))
1667ec681f3Smrg         continue;
1677ec681f3Smrg      unreachable("Unsupported color clear.");
1687ec681f3Smrg   }
1697ec681f3Smrg}
1707ec681f3Smrg
1717ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
1727ec681f3Smrgv3dv_CmdClearDepthStencilImage(VkCommandBuffer commandBuffer,
1737ec681f3Smrg                               VkImage _image,
1747ec681f3Smrg                               VkImageLayout imageLayout,
1757ec681f3Smrg                               const VkClearDepthStencilValue *pDepthStencil,
1767ec681f3Smrg                               uint32_t rangeCount,
1777ec681f3Smrg                               const VkImageSubresourceRange *pRanges)
1787ec681f3Smrg{
1797ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
1807ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_image, image, _image);
1817ec681f3Smrg
1827ec681f3Smrg   const VkClearValue clear_value = {
1837ec681f3Smrg      .depthStencil = *pDepthStencil,
1847ec681f3Smrg   };
1857ec681f3Smrg
1867ec681f3Smrg   for (uint32_t i = 0; i < rangeCount; i++) {
1877ec681f3Smrg      if (clear_image_tlb(cmd_buffer, image, &clear_value, &pRanges[i]))
1887ec681f3Smrg         continue;
1897ec681f3Smrg      unreachable("Unsupported depth/stencil clear.");
1907ec681f3Smrg   }
1917ec681f3Smrg}
1927ec681f3Smrg
1937ec681f3Smrgstatic void
1947ec681f3Smrgdestroy_color_clear_pipeline(VkDevice _device,
1957ec681f3Smrg                             uint64_t pipeline,
1967ec681f3Smrg                             VkAllocationCallbacks *alloc)
1977ec681f3Smrg{
1987ec681f3Smrg   struct v3dv_meta_color_clear_pipeline *p =
1997ec681f3Smrg      (struct v3dv_meta_color_clear_pipeline *) (uintptr_t) pipeline;
2007ec681f3Smrg   v3dv_DestroyPipeline(_device, p->pipeline, alloc);
2017ec681f3Smrg   if (p->cached)
2027ec681f3Smrg      v3dv_DestroyRenderPass(_device, p->pass, alloc);
2037ec681f3Smrg   vk_free(alloc, p);
2047ec681f3Smrg}
2057ec681f3Smrg
2067ec681f3Smrgstatic void
2077ec681f3Smrgdestroy_depth_clear_pipeline(VkDevice _device,
2087ec681f3Smrg                             struct v3dv_meta_depth_clear_pipeline *p,
2097ec681f3Smrg                             VkAllocationCallbacks *alloc)
2107ec681f3Smrg{
2117ec681f3Smrg   v3dv_DestroyPipeline(_device, p->pipeline, alloc);
2127ec681f3Smrg   vk_free(alloc, p);
2137ec681f3Smrg}
2147ec681f3Smrg
2157ec681f3Smrgstatic VkResult
2167ec681f3Smrgcreate_color_clear_pipeline_layout(struct v3dv_device *device,
2177ec681f3Smrg                                   VkPipelineLayout *pipeline_layout)
2187ec681f3Smrg{
2197ec681f3Smrg   /* FIXME: this is abusing a bit the API, since not all of our clear
2207ec681f3Smrg    * pipelines have a geometry shader. We could create 2 different pipeline
2217ec681f3Smrg    * layouts, but this works for us for now.
2227ec681f3Smrg    */
2237ec681f3Smrg   VkPushConstantRange ranges[2] = {
2247ec681f3Smrg      { VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16 },
2257ec681f3Smrg      { VK_SHADER_STAGE_GEOMETRY_BIT, 16, 4 },
2267ec681f3Smrg   };
2277ec681f3Smrg
2287ec681f3Smrg   VkPipelineLayoutCreateInfo info = {
2297ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2307ec681f3Smrg      .setLayoutCount = 0,
2317ec681f3Smrg      .pushConstantRangeCount = 2,
2327ec681f3Smrg      .pPushConstantRanges = ranges,
2337ec681f3Smrg   };
2347ec681f3Smrg
2357ec681f3Smrg   return v3dv_CreatePipelineLayout(v3dv_device_to_handle(device),
2367ec681f3Smrg                                    &info, &device->vk.alloc, pipeline_layout);
2377ec681f3Smrg}
2387ec681f3Smrg
2397ec681f3Smrgstatic VkResult
2407ec681f3Smrgcreate_depth_clear_pipeline_layout(struct v3dv_device *device,
2417ec681f3Smrg                                   VkPipelineLayout *pipeline_layout)
2427ec681f3Smrg{
2437ec681f3Smrg   /* FIXME: this is abusing a bit the API, since not all of our clear
2447ec681f3Smrg    * pipelines have a geometry shader. We could create 2 different pipeline
2457ec681f3Smrg    * layouts, but this works for us for now.
2467ec681f3Smrg    */
2477ec681f3Smrg   VkPushConstantRange ranges[2] = {
2487ec681f3Smrg      { VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4 },
2497ec681f3Smrg      { VK_SHADER_STAGE_GEOMETRY_BIT, 4, 4 },
2507ec681f3Smrg   };
2517ec681f3Smrg
2527ec681f3Smrg   VkPipelineLayoutCreateInfo info = {
2537ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2547ec681f3Smrg      .setLayoutCount = 0,
2557ec681f3Smrg      .pushConstantRangeCount = 2,
2567ec681f3Smrg      .pPushConstantRanges = ranges
2577ec681f3Smrg   };
2587ec681f3Smrg
2597ec681f3Smrg   return v3dv_CreatePipelineLayout(v3dv_device_to_handle(device),
2607ec681f3Smrg                                    &info, &device->vk.alloc, pipeline_layout);
2617ec681f3Smrg}
2627ec681f3Smrg
2637ec681f3Smrgvoid
2647ec681f3Smrgv3dv_meta_clear_init(struct v3dv_device *device)
2657ec681f3Smrg{
2667ec681f3Smrg   device->meta.color_clear.cache =
2677ec681f3Smrg      _mesa_hash_table_create(NULL, u64_hash, u64_compare);
2687ec681f3Smrg
2697ec681f3Smrg   create_color_clear_pipeline_layout(device,
2707ec681f3Smrg                                      &device->meta.color_clear.p_layout);
2717ec681f3Smrg
2727ec681f3Smrg   device->meta.depth_clear.cache =
2737ec681f3Smrg      _mesa_hash_table_create(NULL, u64_hash, u64_compare);
2747ec681f3Smrg
2757ec681f3Smrg   create_depth_clear_pipeline_layout(device,
2767ec681f3Smrg                                      &device->meta.depth_clear.p_layout);
2777ec681f3Smrg}
2787ec681f3Smrg
2797ec681f3Smrgvoid
2807ec681f3Smrgv3dv_meta_clear_finish(struct v3dv_device *device)
2817ec681f3Smrg{
2827ec681f3Smrg   VkDevice _device = v3dv_device_to_handle(device);
2837ec681f3Smrg
2847ec681f3Smrg   hash_table_foreach(device->meta.color_clear.cache, entry) {
2857ec681f3Smrg      struct v3dv_meta_color_clear_pipeline *item = entry->data;
2867ec681f3Smrg      destroy_color_clear_pipeline(_device, (uintptr_t)item, &device->vk.alloc);
2877ec681f3Smrg   }
2887ec681f3Smrg   _mesa_hash_table_destroy(device->meta.color_clear.cache, NULL);
2897ec681f3Smrg
2907ec681f3Smrg   if (device->meta.color_clear.p_layout) {
2917ec681f3Smrg      v3dv_DestroyPipelineLayout(_device, device->meta.color_clear.p_layout,
2927ec681f3Smrg                                 &device->vk.alloc);
2937ec681f3Smrg   }
2947ec681f3Smrg
2957ec681f3Smrg   hash_table_foreach(device->meta.depth_clear.cache, entry) {
2967ec681f3Smrg      struct v3dv_meta_depth_clear_pipeline *item = entry->data;
2977ec681f3Smrg      destroy_depth_clear_pipeline(_device, item, &device->vk.alloc);
2987ec681f3Smrg   }
2997ec681f3Smrg   _mesa_hash_table_destroy(device->meta.depth_clear.cache, NULL);
3007ec681f3Smrg
3017ec681f3Smrg   if (device->meta.depth_clear.p_layout) {
3027ec681f3Smrg      v3dv_DestroyPipelineLayout(_device, device->meta.depth_clear.p_layout,
3037ec681f3Smrg                                 &device->vk.alloc);
3047ec681f3Smrg   }
3057ec681f3Smrg}
3067ec681f3Smrg
3077ec681f3Smrgstatic nir_ssa_def *
3087ec681f3Smrggen_rect_vertices(nir_builder *b)
3097ec681f3Smrg{
3107ec681f3Smrg   nir_ssa_def *vertex_id = nir_load_vertex_id(b);
3117ec681f3Smrg
3127ec681f3Smrg   /* vertex 0: -1.0, -1.0
3137ec681f3Smrg    * vertex 1: -1.0,  1.0
3147ec681f3Smrg    * vertex 2:  1.0, -1.0
3157ec681f3Smrg    * vertex 3:  1.0,  1.0
3167ec681f3Smrg    *
3177ec681f3Smrg    * so:
3187ec681f3Smrg    *
3197ec681f3Smrg    * channel 0 is vertex_id < 2 ? -1.0 :  1.0
3207ec681f3Smrg    * channel 1 is vertex id & 1 ?  1.0 : -1.0
3217ec681f3Smrg    */
3227ec681f3Smrg
3237ec681f3Smrg   nir_ssa_def *one = nir_imm_int(b, 1);
3247ec681f3Smrg   nir_ssa_def *c0cmp = nir_ilt(b, vertex_id, nir_imm_int(b, 2));
3257ec681f3Smrg   nir_ssa_def *c1cmp = nir_ieq(b, nir_iand(b, vertex_id, one), one);
3267ec681f3Smrg
3277ec681f3Smrg   nir_ssa_def *comp[4];
3287ec681f3Smrg   comp[0] = nir_bcsel(b, c0cmp,
3297ec681f3Smrg                       nir_imm_float(b, -1.0f),
3307ec681f3Smrg                       nir_imm_float(b, 1.0f));
3317ec681f3Smrg
3327ec681f3Smrg   comp[1] = nir_bcsel(b, c1cmp,
3337ec681f3Smrg                       nir_imm_float(b, 1.0f),
3347ec681f3Smrg                       nir_imm_float(b, -1.0f));
3357ec681f3Smrg   comp[2] = nir_imm_float(b, 0.0f);
3367ec681f3Smrg   comp[3] = nir_imm_float(b, 1.0f);
3377ec681f3Smrg   return nir_vec(b, comp, 4);
3387ec681f3Smrg}
3397ec681f3Smrg
3407ec681f3Smrgstatic nir_shader *
3417ec681f3Smrgget_clear_rect_vs()
3427ec681f3Smrg{
3437ec681f3Smrg   const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
3447ec681f3Smrg   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, options,
3457ec681f3Smrg                                                  "meta clear vs");
3467ec681f3Smrg
3477ec681f3Smrg   const struct glsl_type *vec4 = glsl_vec4_type();
3487ec681f3Smrg   nir_variable *vs_out_pos =
3497ec681f3Smrg      nir_variable_create(b.shader, nir_var_shader_out, vec4, "gl_Position");
3507ec681f3Smrg   vs_out_pos->data.location = VARYING_SLOT_POS;
3517ec681f3Smrg
3527ec681f3Smrg   nir_ssa_def *pos = gen_rect_vertices(&b);
3537ec681f3Smrg   nir_store_var(&b, vs_out_pos, pos, 0xf);
3547ec681f3Smrg
3557ec681f3Smrg   return b.shader;
3567ec681f3Smrg}
3577ec681f3Smrg
3587ec681f3Smrgstatic nir_shader *
3597ec681f3Smrgget_clear_rect_gs(uint32_t push_constant_layer_base)
3607ec681f3Smrg{
3617ec681f3Smrg   /* FIXME: this creates a geometry shader that takes the index of a single
3627ec681f3Smrg    * layer to clear from push constants, so we need to emit a draw call for
3637ec681f3Smrg    * each layer that we want to clear. We could actually do better and have it
3647ec681f3Smrg    * take a range of layers and then emit one triangle per layer to clear,
3657ec681f3Smrg    * however, if we were to do this we would need to be careful not to exceed
3667ec681f3Smrg    * the maximum number of output vertices allowed in a geometry shader.
3677ec681f3Smrg    */
3687ec681f3Smrg   const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
3697ec681f3Smrg   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, options,
3707ec681f3Smrg                                                  "meta clear gs");
3717ec681f3Smrg   nir_shader *nir = b.shader;
3727ec681f3Smrg   nir->info.inputs_read = 1ull << VARYING_SLOT_POS;
3737ec681f3Smrg   nir->info.outputs_written = (1ull << VARYING_SLOT_POS) |
3747ec681f3Smrg                               (1ull << VARYING_SLOT_LAYER);
3757ec681f3Smrg   nir->info.gs.input_primitive = GL_TRIANGLES;
3767ec681f3Smrg   nir->info.gs.output_primitive = GL_TRIANGLE_STRIP;
3777ec681f3Smrg   nir->info.gs.vertices_in = 3;
3787ec681f3Smrg   nir->info.gs.vertices_out = 3;
3797ec681f3Smrg   nir->info.gs.invocations = 1;
3807ec681f3Smrg   nir->info.gs.active_stream_mask = 0x1;
3817ec681f3Smrg
3827ec681f3Smrg   /* in vec4 gl_Position[3] */
3837ec681f3Smrg   nir_variable *gs_in_pos =
3847ec681f3Smrg      nir_variable_create(b.shader, nir_var_shader_in,
3857ec681f3Smrg                          glsl_array_type(glsl_vec4_type(), 3, 0),
3867ec681f3Smrg                          "in_gl_Position");
3877ec681f3Smrg   gs_in_pos->data.location = VARYING_SLOT_POS;
3887ec681f3Smrg
3897ec681f3Smrg   /* out vec4 gl_Position */
3907ec681f3Smrg   nir_variable *gs_out_pos =
3917ec681f3Smrg      nir_variable_create(b.shader, nir_var_shader_out, glsl_vec4_type(),
3927ec681f3Smrg                          "out_gl_Position");
3937ec681f3Smrg   gs_out_pos->data.location = VARYING_SLOT_POS;
3947ec681f3Smrg
3957ec681f3Smrg   /* out float gl_Layer */
3967ec681f3Smrg   nir_variable *gs_out_layer =
3977ec681f3Smrg      nir_variable_create(b.shader, nir_var_shader_out, glsl_float_type(),
3987ec681f3Smrg                          "out_gl_Layer");
3997ec681f3Smrg   gs_out_layer->data.location = VARYING_SLOT_LAYER;
4007ec681f3Smrg
4017ec681f3Smrg   /* Emit output triangle */
4027ec681f3Smrg   for (uint32_t i = 0; i < 3; i++) {
4037ec681f3Smrg      /* gl_Position from shader input */
4047ec681f3Smrg      nir_deref_instr *in_pos_i =
4057ec681f3Smrg         nir_build_deref_array_imm(&b, nir_build_deref_var(&b, gs_in_pos), i);
4067ec681f3Smrg      nir_copy_deref(&b, nir_build_deref_var(&b, gs_out_pos), in_pos_i);
4077ec681f3Smrg
4087ec681f3Smrg      /* gl_Layer from push constants */
4097ec681f3Smrg      nir_ssa_def *layer =
4107ec681f3Smrg         nir_load_push_constant(&b, 1, 32, nir_imm_int(&b, 0),
4117ec681f3Smrg                                .base = push_constant_layer_base, .range = 4);
4127ec681f3Smrg      nir_store_var(&b, gs_out_layer, layer, 0x1);
4137ec681f3Smrg
4147ec681f3Smrg      nir_emit_vertex(&b, 0);
4157ec681f3Smrg   }
4167ec681f3Smrg
4177ec681f3Smrg   nir_end_primitive(&b, 0);
4187ec681f3Smrg
4197ec681f3Smrg   return nir;
4207ec681f3Smrg}
4217ec681f3Smrg
4227ec681f3Smrgstatic nir_shader *
4237ec681f3Smrgget_color_clear_rect_fs(uint32_t rt_idx, VkFormat format)
4247ec681f3Smrg{
4257ec681f3Smrg   const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
4267ec681f3Smrg   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, options,
4277ec681f3Smrg                                                  "meta clear fs");
4287ec681f3Smrg
4297ec681f3Smrg   enum pipe_format pformat = vk_format_to_pipe_format(format);
4307ec681f3Smrg   const struct glsl_type *fs_out_type =
4317ec681f3Smrg      util_format_is_float(pformat) ? glsl_vec4_type() : glsl_uvec4_type();
4327ec681f3Smrg
4337ec681f3Smrg   nir_variable *fs_out_color =
4347ec681f3Smrg      nir_variable_create(b.shader, nir_var_shader_out, fs_out_type, "out_color");
4357ec681f3Smrg   fs_out_color->data.location = FRAG_RESULT_DATA0 + rt_idx;
4367ec681f3Smrg
4377ec681f3Smrg   nir_ssa_def *color_load = nir_load_push_constant(&b, 4, 32, nir_imm_int(&b, 0), .base = 0, .range = 16);
4387ec681f3Smrg   nir_store_var(&b, fs_out_color, color_load, 0xf);
4397ec681f3Smrg
4407ec681f3Smrg   return b.shader;
4417ec681f3Smrg}
4427ec681f3Smrg
4437ec681f3Smrgstatic nir_shader *
4447ec681f3Smrgget_depth_clear_rect_fs()
4457ec681f3Smrg{
4467ec681f3Smrg   const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
4477ec681f3Smrg   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, options,
4487ec681f3Smrg                                                  "meta depth clear fs");
4497ec681f3Smrg
4507ec681f3Smrg   nir_variable *fs_out_depth =
4517ec681f3Smrg      nir_variable_create(b.shader, nir_var_shader_out, glsl_float_type(),
4527ec681f3Smrg                          "out_depth");
4537ec681f3Smrg   fs_out_depth->data.location = FRAG_RESULT_DEPTH;
4547ec681f3Smrg
4557ec681f3Smrg   nir_ssa_def *depth_load =
4567ec681f3Smrg      nir_load_push_constant(&b, 1, 32, nir_imm_int(&b, 0), .base = 0, .range = 4);
4577ec681f3Smrg
4587ec681f3Smrg   nir_store_var(&b, fs_out_depth, depth_load, 0x1);
4597ec681f3Smrg
4607ec681f3Smrg   return b.shader;
4617ec681f3Smrg}
4627ec681f3Smrg
4637ec681f3Smrgstatic VkResult
4647ec681f3Smrgcreate_pipeline(struct v3dv_device *device,
4657ec681f3Smrg                struct v3dv_render_pass *pass,
4667ec681f3Smrg                uint32_t subpass_idx,
4677ec681f3Smrg                uint32_t samples,
4687ec681f3Smrg                struct nir_shader *vs_nir,
4697ec681f3Smrg                struct nir_shader *gs_nir,
4707ec681f3Smrg                struct nir_shader *fs_nir,
4717ec681f3Smrg                const VkPipelineVertexInputStateCreateInfo *vi_state,
4727ec681f3Smrg                const VkPipelineDepthStencilStateCreateInfo *ds_state,
4737ec681f3Smrg                const VkPipelineColorBlendStateCreateInfo *cb_state,
4747ec681f3Smrg                const VkPipelineLayout layout,
4757ec681f3Smrg                VkPipeline *pipeline)
4767ec681f3Smrg{
4777ec681f3Smrg   VkPipelineShaderStageCreateInfo stages[3] = { 0 };
4787ec681f3Smrg   struct vk_shader_module vs_m;
4797ec681f3Smrg   struct vk_shader_module gs_m;
4807ec681f3Smrg   struct vk_shader_module fs_m;
4817ec681f3Smrg
4827ec681f3Smrg   uint32_t stage_count = 0;
4837ec681f3Smrg   v3dv_shader_module_internal_init(device, &vs_m, vs_nir);
4847ec681f3Smrg   stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
4857ec681f3Smrg   stages[stage_count].stage = VK_SHADER_STAGE_VERTEX_BIT;
4867ec681f3Smrg   stages[stage_count].module = vk_shader_module_to_handle(&vs_m);
4877ec681f3Smrg   stages[stage_count].pName = "main";
4887ec681f3Smrg   stage_count++;
4897ec681f3Smrg
4907ec681f3Smrg   if (gs_nir) {
4917ec681f3Smrg      v3dv_shader_module_internal_init(device, &gs_m, gs_nir);
4927ec681f3Smrg      stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
4937ec681f3Smrg      stages[stage_count].stage = VK_SHADER_STAGE_GEOMETRY_BIT;
4947ec681f3Smrg      stages[stage_count].module = vk_shader_module_to_handle(&gs_m);
4957ec681f3Smrg      stages[stage_count].pName = "main";
4967ec681f3Smrg      stage_count++;
4977ec681f3Smrg   }
4987ec681f3Smrg
4997ec681f3Smrg   if (fs_nir) {
5007ec681f3Smrg      v3dv_shader_module_internal_init(device, &fs_m, fs_nir);
5017ec681f3Smrg      stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
5027ec681f3Smrg      stages[stage_count].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
5037ec681f3Smrg      stages[stage_count].module = vk_shader_module_to_handle(&fs_m);
5047ec681f3Smrg      stages[stage_count].pName = "main";
5057ec681f3Smrg      stage_count++;
5067ec681f3Smrg   }
5077ec681f3Smrg
5087ec681f3Smrg   VkGraphicsPipelineCreateInfo info = {
5097ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
5107ec681f3Smrg
5117ec681f3Smrg      .stageCount = stage_count,
5127ec681f3Smrg      .pStages = stages,
5137ec681f3Smrg
5147ec681f3Smrg      .pVertexInputState = vi_state,
5157ec681f3Smrg
5167ec681f3Smrg      .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
5177ec681f3Smrg         .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
5187ec681f3Smrg         .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
5197ec681f3Smrg         .primitiveRestartEnable = false,
5207ec681f3Smrg      },
5217ec681f3Smrg
5227ec681f3Smrg      .pViewportState = &(VkPipelineViewportStateCreateInfo) {
5237ec681f3Smrg         .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
5247ec681f3Smrg         .viewportCount = 1,
5257ec681f3Smrg         .scissorCount = 1,
5267ec681f3Smrg      },
5277ec681f3Smrg
5287ec681f3Smrg      .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
5297ec681f3Smrg         .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
5307ec681f3Smrg         .rasterizerDiscardEnable = false,
5317ec681f3Smrg         .polygonMode = VK_POLYGON_MODE_FILL,
5327ec681f3Smrg         .cullMode = VK_CULL_MODE_NONE,
5337ec681f3Smrg         .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
5347ec681f3Smrg         .depthBiasEnable = false,
5357ec681f3Smrg      },
5367ec681f3Smrg
5377ec681f3Smrg      .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
5387ec681f3Smrg         .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
5397ec681f3Smrg         .rasterizationSamples = samples,
5407ec681f3Smrg         .sampleShadingEnable = false,
5417ec681f3Smrg         .pSampleMask = NULL,
5427ec681f3Smrg         .alphaToCoverageEnable = false,
5437ec681f3Smrg         .alphaToOneEnable = false,
5447ec681f3Smrg      },
5457ec681f3Smrg
5467ec681f3Smrg      .pDepthStencilState = ds_state,
5477ec681f3Smrg
5487ec681f3Smrg      .pColorBlendState = cb_state,
5497ec681f3Smrg
5507ec681f3Smrg      /* The meta clear pipeline declares all state as dynamic.
5517ec681f3Smrg       * As a consequence, vkCmdBindPipeline writes no dynamic state
5527ec681f3Smrg       * to the cmd buffer. Therefore, at the end of the meta clear,
5537ec681f3Smrg       * we need only restore dynamic state that was vkCmdSet.
5547ec681f3Smrg       */
5557ec681f3Smrg      .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
5567ec681f3Smrg         .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
5577ec681f3Smrg         .dynamicStateCount = 6,
5587ec681f3Smrg         .pDynamicStates = (VkDynamicState[]) {
5597ec681f3Smrg            VK_DYNAMIC_STATE_VIEWPORT,
5607ec681f3Smrg            VK_DYNAMIC_STATE_SCISSOR,
5617ec681f3Smrg            VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
5627ec681f3Smrg            VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
5637ec681f3Smrg            VK_DYNAMIC_STATE_STENCIL_REFERENCE,
5647ec681f3Smrg            VK_DYNAMIC_STATE_BLEND_CONSTANTS,
5657ec681f3Smrg            VK_DYNAMIC_STATE_DEPTH_BIAS,
5667ec681f3Smrg            VK_DYNAMIC_STATE_LINE_WIDTH,
5677ec681f3Smrg         },
5687ec681f3Smrg      },
5697ec681f3Smrg
5707ec681f3Smrg      .flags = 0,
5717ec681f3Smrg      .layout = layout,
5727ec681f3Smrg      .renderPass = v3dv_render_pass_to_handle(pass),
5737ec681f3Smrg      .subpass = subpass_idx,
5747ec681f3Smrg   };
5757ec681f3Smrg
5767ec681f3Smrg   VkResult result =
5777ec681f3Smrg      v3dv_CreateGraphicsPipelines(v3dv_device_to_handle(device),
5787ec681f3Smrg                                   VK_NULL_HANDLE,
5797ec681f3Smrg                                   1, &info,
5807ec681f3Smrg                                   &device->vk.alloc,
5817ec681f3Smrg                                   pipeline);
5827ec681f3Smrg
5837ec681f3Smrg   ralloc_free(vs_nir);
5847ec681f3Smrg   ralloc_free(fs_nir);
5857ec681f3Smrg
5867ec681f3Smrg   return result;
5877ec681f3Smrg}
5887ec681f3Smrg
5897ec681f3Smrgstatic VkResult
5907ec681f3Smrgcreate_color_clear_pipeline(struct v3dv_device *device,
5917ec681f3Smrg                            struct v3dv_render_pass *pass,
5927ec681f3Smrg                            uint32_t subpass_idx,
5937ec681f3Smrg                            uint32_t rt_idx,
5947ec681f3Smrg                            VkFormat format,
5957ec681f3Smrg                            uint32_t samples,
5967ec681f3Smrg                            uint32_t components,
5977ec681f3Smrg                            bool is_layered,
5987ec681f3Smrg                            VkPipelineLayout pipeline_layout,
5997ec681f3Smrg                            VkPipeline *pipeline)
6007ec681f3Smrg{
6017ec681f3Smrg   nir_shader *vs_nir = get_clear_rect_vs();
6027ec681f3Smrg   nir_shader *fs_nir = get_color_clear_rect_fs(rt_idx, format);
6037ec681f3Smrg   nir_shader *gs_nir = is_layered ? get_clear_rect_gs(16) : NULL;
6047ec681f3Smrg
6057ec681f3Smrg   const VkPipelineVertexInputStateCreateInfo vi_state = {
6067ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
6077ec681f3Smrg      .vertexBindingDescriptionCount = 0,
6087ec681f3Smrg      .vertexAttributeDescriptionCount = 0,
6097ec681f3Smrg   };
6107ec681f3Smrg
6117ec681f3Smrg   const VkPipelineDepthStencilStateCreateInfo ds_state = {
6127ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
6137ec681f3Smrg      .depthTestEnable = false,
6147ec681f3Smrg      .depthWriteEnable = false,
6157ec681f3Smrg      .depthBoundsTestEnable = false,
6167ec681f3Smrg      .stencilTestEnable = false,
6177ec681f3Smrg   };
6187ec681f3Smrg
6197ec681f3Smrg   assert(subpass_idx < pass->subpass_count);
6207ec681f3Smrg   const uint32_t color_count = pass->subpasses[subpass_idx].color_count;
6217ec681f3Smrg   assert(rt_idx < color_count);
6227ec681f3Smrg
6237ec681f3Smrg   VkPipelineColorBlendAttachmentState blend_att_state[V3D_MAX_DRAW_BUFFERS];
6247ec681f3Smrg   for (uint32_t i = 0; i < color_count; i++) {
6257ec681f3Smrg      blend_att_state[i] = (VkPipelineColorBlendAttachmentState) {
6267ec681f3Smrg         .blendEnable = false,
6277ec681f3Smrg         .colorWriteMask = i == rt_idx ? components : 0,
6287ec681f3Smrg      };
6297ec681f3Smrg   }
6307ec681f3Smrg
6317ec681f3Smrg   const VkPipelineColorBlendStateCreateInfo cb_state = {
6327ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
6337ec681f3Smrg      .logicOpEnable = false,
6347ec681f3Smrg      .attachmentCount = color_count,
6357ec681f3Smrg      .pAttachments = blend_att_state
6367ec681f3Smrg   };
6377ec681f3Smrg
6387ec681f3Smrg   return create_pipeline(device,
6397ec681f3Smrg                          pass, subpass_idx,
6407ec681f3Smrg                          samples,
6417ec681f3Smrg                          vs_nir, gs_nir, fs_nir,
6427ec681f3Smrg                          &vi_state,
6437ec681f3Smrg                          &ds_state,
6447ec681f3Smrg                          &cb_state,
6457ec681f3Smrg                          pipeline_layout,
6467ec681f3Smrg                          pipeline);
6477ec681f3Smrg}
6487ec681f3Smrg
6497ec681f3Smrgstatic VkResult
6507ec681f3Smrgcreate_depth_clear_pipeline(struct v3dv_device *device,
6517ec681f3Smrg                            VkImageAspectFlags aspects,
6527ec681f3Smrg                            struct v3dv_render_pass *pass,
6537ec681f3Smrg                            uint32_t subpass_idx,
6547ec681f3Smrg                            uint32_t samples,
6557ec681f3Smrg                            bool is_layered,
6567ec681f3Smrg                            VkPipelineLayout pipeline_layout,
6577ec681f3Smrg                            VkPipeline *pipeline)
6587ec681f3Smrg{
6597ec681f3Smrg   const bool has_depth = aspects & VK_IMAGE_ASPECT_DEPTH_BIT;
6607ec681f3Smrg   const bool has_stencil = aspects & VK_IMAGE_ASPECT_STENCIL_BIT;
6617ec681f3Smrg   assert(has_depth || has_stencil);
6627ec681f3Smrg
6637ec681f3Smrg   nir_shader *vs_nir = get_clear_rect_vs();
6647ec681f3Smrg   nir_shader *fs_nir = has_depth ? get_depth_clear_rect_fs() : NULL;
6657ec681f3Smrg   nir_shader *gs_nir = is_layered ? get_clear_rect_gs(4) : NULL;
6667ec681f3Smrg
6677ec681f3Smrg   const VkPipelineVertexInputStateCreateInfo vi_state = {
6687ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
6697ec681f3Smrg      .vertexBindingDescriptionCount = 0,
6707ec681f3Smrg      .vertexAttributeDescriptionCount = 0,
6717ec681f3Smrg   };
6727ec681f3Smrg
6737ec681f3Smrg   const VkPipelineDepthStencilStateCreateInfo ds_state = {
6747ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
6757ec681f3Smrg      .depthTestEnable = has_depth,
6767ec681f3Smrg      .depthWriteEnable = has_depth,
6777ec681f3Smrg      .depthCompareOp = VK_COMPARE_OP_ALWAYS,
6787ec681f3Smrg      .depthBoundsTestEnable = false,
6797ec681f3Smrg      .stencilTestEnable = has_stencil,
6807ec681f3Smrg      .front = {
6817ec681f3Smrg         .passOp = VK_STENCIL_OP_REPLACE,
6827ec681f3Smrg         .compareOp = VK_COMPARE_OP_ALWAYS,
6837ec681f3Smrg         /* compareMask, writeMask and reference are dynamic state */
6847ec681f3Smrg      },
6857ec681f3Smrg      .back = { 0 },
6867ec681f3Smrg   };
6877ec681f3Smrg
6887ec681f3Smrg   assert(subpass_idx < pass->subpass_count);
6897ec681f3Smrg   VkPipelineColorBlendAttachmentState blend_att_state[V3D_MAX_DRAW_BUFFERS] = { 0 };
6907ec681f3Smrg   const VkPipelineColorBlendStateCreateInfo cb_state = {
6917ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
6927ec681f3Smrg      .logicOpEnable = false,
6937ec681f3Smrg      .attachmentCount = pass->subpasses[subpass_idx].color_count,
6947ec681f3Smrg      .pAttachments = blend_att_state,
6957ec681f3Smrg   };
6967ec681f3Smrg
6977ec681f3Smrg   return create_pipeline(device,
6987ec681f3Smrg                          pass, subpass_idx,
6997ec681f3Smrg                          samples,
7007ec681f3Smrg                          vs_nir, gs_nir, fs_nir,
7017ec681f3Smrg                          &vi_state,
7027ec681f3Smrg                          &ds_state,
7037ec681f3Smrg                          &cb_state,
7047ec681f3Smrg                          pipeline_layout,
7057ec681f3Smrg                          pipeline);
7067ec681f3Smrg}
7077ec681f3Smrg
7087ec681f3Smrgstatic VkResult
7097ec681f3Smrgcreate_color_clear_render_pass(struct v3dv_device *device,
7107ec681f3Smrg                               uint32_t rt_idx,
7117ec681f3Smrg                               VkFormat format,
7127ec681f3Smrg                               uint32_t samples,
7137ec681f3Smrg                               VkRenderPass *pass)
7147ec681f3Smrg{
7157ec681f3Smrg   VkAttachmentDescription att = {
7167ec681f3Smrg      .format = format,
7177ec681f3Smrg      .samples = samples,
7187ec681f3Smrg      .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
7197ec681f3Smrg      .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
7207ec681f3Smrg      .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
7217ec681f3Smrg      .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
7227ec681f3Smrg   };
7237ec681f3Smrg
7247ec681f3Smrg   VkAttachmentReference att_ref = {
7257ec681f3Smrg      .attachment = rt_idx,
7267ec681f3Smrg      .layout = VK_IMAGE_LAYOUT_GENERAL,
7277ec681f3Smrg   };
7287ec681f3Smrg
7297ec681f3Smrg   VkSubpassDescription subpass = {
7307ec681f3Smrg      .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
7317ec681f3Smrg      .inputAttachmentCount = 0,
7327ec681f3Smrg      .colorAttachmentCount = 1,
7337ec681f3Smrg      .pColorAttachments = &att_ref,
7347ec681f3Smrg      .pResolveAttachments = NULL,
7357ec681f3Smrg      .pDepthStencilAttachment = NULL,
7367ec681f3Smrg      .preserveAttachmentCount = 0,
7377ec681f3Smrg      .pPreserveAttachments = NULL,
7387ec681f3Smrg   };
7397ec681f3Smrg
7407ec681f3Smrg   VkRenderPassCreateInfo info = {
7417ec681f3Smrg      .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
7427ec681f3Smrg      .attachmentCount = 1,
7437ec681f3Smrg      .pAttachments = &att,
7447ec681f3Smrg      .subpassCount = 1,
7457ec681f3Smrg      .pSubpasses = &subpass,
7467ec681f3Smrg      .dependencyCount = 0,
7477ec681f3Smrg      .pDependencies = NULL,
7487ec681f3Smrg   };
7497ec681f3Smrg
7507ec681f3Smrg   return v3dv_CreateRenderPass(v3dv_device_to_handle(device),
7517ec681f3Smrg                                &info, &device->vk.alloc, pass);
7527ec681f3Smrg}
7537ec681f3Smrg
7547ec681f3Smrgstatic inline uint64_t
7557ec681f3Smrgget_color_clear_pipeline_cache_key(uint32_t rt_idx,
7567ec681f3Smrg                                   VkFormat format,
7577ec681f3Smrg                                   uint32_t samples,
7587ec681f3Smrg                                   uint32_t components,
7597ec681f3Smrg                                   bool is_layered)
7607ec681f3Smrg{
7617ec681f3Smrg   assert(rt_idx < V3D_MAX_DRAW_BUFFERS);
7627ec681f3Smrg
7637ec681f3Smrg   uint64_t key = 0;
7647ec681f3Smrg   uint32_t bit_offset = 0;
7657ec681f3Smrg
7667ec681f3Smrg   key |= rt_idx;
7677ec681f3Smrg   bit_offset += 2;
7687ec681f3Smrg
7697ec681f3Smrg   key |= ((uint64_t) format) << bit_offset;
7707ec681f3Smrg   bit_offset += 32;
7717ec681f3Smrg
7727ec681f3Smrg   key |= ((uint64_t) samples) << bit_offset;
7737ec681f3Smrg   bit_offset += 4;
7747ec681f3Smrg
7757ec681f3Smrg   key |= ((uint64_t) components) << bit_offset;
7767ec681f3Smrg   bit_offset += 4;
7777ec681f3Smrg
7787ec681f3Smrg   key |= (is_layered ? 1ull : 0ull) << bit_offset;
7797ec681f3Smrg   bit_offset += 1;
7807ec681f3Smrg
7817ec681f3Smrg   assert(bit_offset <= 64);
7827ec681f3Smrg   return key;
7837ec681f3Smrg}
7847ec681f3Smrg
7857ec681f3Smrgstatic inline uint64_t
7867ec681f3Smrgget_depth_clear_pipeline_cache_key(VkImageAspectFlags aspects,
7877ec681f3Smrg                                   VkFormat format,
7887ec681f3Smrg                                   uint32_t samples,
7897ec681f3Smrg                                   bool is_layered)
7907ec681f3Smrg{
7917ec681f3Smrg   uint64_t key = 0;
7927ec681f3Smrg   uint32_t bit_offset = 0;
7937ec681f3Smrg
7947ec681f3Smrg   key |= format;
7957ec681f3Smrg   bit_offset += 32;
7967ec681f3Smrg
7977ec681f3Smrg   key |= ((uint64_t) samples) << bit_offset;
7987ec681f3Smrg   bit_offset += 4;
7997ec681f3Smrg
8007ec681f3Smrg   const bool has_depth = (aspects & VK_IMAGE_ASPECT_DEPTH_BIT) ? 1 : 0;
8017ec681f3Smrg   key |= ((uint64_t) has_depth) << bit_offset;
8027ec681f3Smrg   bit_offset++;
8037ec681f3Smrg
8047ec681f3Smrg   const bool has_stencil = (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) ? 1 : 0;
8057ec681f3Smrg   key |= ((uint64_t) has_stencil) << bit_offset;
8067ec681f3Smrg   bit_offset++;;
8077ec681f3Smrg
8087ec681f3Smrg   key |= (is_layered ? 1ull : 0ull) << bit_offset;
8097ec681f3Smrg   bit_offset += 1;
8107ec681f3Smrg
8117ec681f3Smrg   assert(bit_offset <= 64);
8127ec681f3Smrg   return key;
8137ec681f3Smrg}
8147ec681f3Smrg
8157ec681f3Smrgstatic VkResult
8167ec681f3Smrgget_color_clear_pipeline(struct v3dv_device *device,
8177ec681f3Smrg                         struct v3dv_render_pass *pass,
8187ec681f3Smrg                         uint32_t subpass_idx,
8197ec681f3Smrg                         uint32_t rt_idx,
8207ec681f3Smrg                         uint32_t attachment_idx,
8217ec681f3Smrg                         VkFormat format,
8227ec681f3Smrg                         uint32_t samples,
8237ec681f3Smrg                         uint32_t components,
8247ec681f3Smrg                         bool is_layered,
8257ec681f3Smrg                         struct v3dv_meta_color_clear_pipeline **pipeline)
8267ec681f3Smrg{
8277ec681f3Smrg   assert(vk_format_is_color(format));
8287ec681f3Smrg
8297ec681f3Smrg   VkResult result = VK_SUCCESS;
8307ec681f3Smrg
8317ec681f3Smrg   /* If pass != NULL it means that we are emitting the clear as a draw call
8327ec681f3Smrg    * in the current pass bound by the application. In that case, we can't
8337ec681f3Smrg    * cache the pipeline, since it will be referencing that pass and the
8347ec681f3Smrg    * application could be destroying it at any point. Hopefully, the perf
8357ec681f3Smrg    * impact is not too big since we still have the device pipeline cache
8367ec681f3Smrg    * around and we won't end up re-compiling the clear shader.
8377ec681f3Smrg    *
8387ec681f3Smrg    * FIXME: alternatively, we could refcount (or maybe clone) the render pass
8397ec681f3Smrg    * provided by the application and include it in the pipeline key setup
8407ec681f3Smrg    * to make caching safe in this scenario, however, based on tests with
8417ec681f3Smrg    * vkQuake3, the fact that we are not caching here doesn't seem to have
8427ec681f3Smrg    * any significant impact in performance, so it might not be worth it.
8437ec681f3Smrg    */
8447ec681f3Smrg   const bool can_cache_pipeline = (pass == NULL);
8457ec681f3Smrg
8467ec681f3Smrg   uint64_t key;
8477ec681f3Smrg   if (can_cache_pipeline) {
8487ec681f3Smrg      key = get_color_clear_pipeline_cache_key(rt_idx, format, samples,
8497ec681f3Smrg                                               components, is_layered);
8507ec681f3Smrg      mtx_lock(&device->meta.mtx);
8517ec681f3Smrg      struct hash_entry *entry =
8527ec681f3Smrg         _mesa_hash_table_search(device->meta.color_clear.cache, &key);
8537ec681f3Smrg      if (entry) {
8547ec681f3Smrg         mtx_unlock(&device->meta.mtx);
8557ec681f3Smrg         *pipeline = entry->data;
8567ec681f3Smrg         return VK_SUCCESS;
8577ec681f3Smrg      }
8587ec681f3Smrg   }
8597ec681f3Smrg
8607ec681f3Smrg   *pipeline = vk_zalloc2(&device->vk.alloc, NULL, sizeof(**pipeline), 8,
8617ec681f3Smrg                          VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
8627ec681f3Smrg
8637ec681f3Smrg   if (*pipeline == NULL) {
8647ec681f3Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
8657ec681f3Smrg      goto fail;
8667ec681f3Smrg   }
8677ec681f3Smrg
8687ec681f3Smrg   if (!pass) {
8697ec681f3Smrg      result = create_color_clear_render_pass(device,
8707ec681f3Smrg                                              rt_idx,
8717ec681f3Smrg                                              format,
8727ec681f3Smrg                                              samples,
8737ec681f3Smrg                                              &(*pipeline)->pass);
8747ec681f3Smrg      if (result != VK_SUCCESS)
8757ec681f3Smrg         goto fail;
8767ec681f3Smrg
8777ec681f3Smrg      pass = v3dv_render_pass_from_handle((*pipeline)->pass);
8787ec681f3Smrg   } else {
8797ec681f3Smrg      (*pipeline)->pass = v3dv_render_pass_to_handle(pass);
8807ec681f3Smrg   }
8817ec681f3Smrg
8827ec681f3Smrg   result = create_color_clear_pipeline(device,
8837ec681f3Smrg                                        pass,
8847ec681f3Smrg                                        subpass_idx,
8857ec681f3Smrg                                        rt_idx,
8867ec681f3Smrg                                        format,
8877ec681f3Smrg                                        samples,
8887ec681f3Smrg                                        components,
8897ec681f3Smrg                                        is_layered,
8907ec681f3Smrg                                        device->meta.color_clear.p_layout,
8917ec681f3Smrg                                        &(*pipeline)->pipeline);
8927ec681f3Smrg   if (result != VK_SUCCESS)
8937ec681f3Smrg      goto fail;
8947ec681f3Smrg
8957ec681f3Smrg   if (can_cache_pipeline) {
8967ec681f3Smrg      (*pipeline)->key = key;
8977ec681f3Smrg      (*pipeline)->cached = true;
8987ec681f3Smrg      _mesa_hash_table_insert(device->meta.color_clear.cache,
8997ec681f3Smrg                              &(*pipeline)->key, *pipeline);
9007ec681f3Smrg
9017ec681f3Smrg      mtx_unlock(&device->meta.mtx);
9027ec681f3Smrg   }
9037ec681f3Smrg
9047ec681f3Smrg   return VK_SUCCESS;
9057ec681f3Smrg
9067ec681f3Smrgfail:
9077ec681f3Smrg   if (can_cache_pipeline)
9087ec681f3Smrg      mtx_unlock(&device->meta.mtx);
9097ec681f3Smrg
9107ec681f3Smrg   VkDevice _device = v3dv_device_to_handle(device);
9117ec681f3Smrg   if (*pipeline) {
9127ec681f3Smrg      if ((*pipeline)->cached)
9137ec681f3Smrg         v3dv_DestroyRenderPass(_device, (*pipeline)->pass, &device->vk.alloc);
9147ec681f3Smrg      if ((*pipeline)->pipeline)
9157ec681f3Smrg         v3dv_DestroyPipeline(_device, (*pipeline)->pipeline, &device->vk.alloc);
9167ec681f3Smrg      vk_free(&device->vk.alloc, *pipeline);
9177ec681f3Smrg      *pipeline = NULL;
9187ec681f3Smrg   }
9197ec681f3Smrg
9207ec681f3Smrg   return result;
9217ec681f3Smrg}
9227ec681f3Smrg
9237ec681f3Smrgstatic VkResult
9247ec681f3Smrgget_depth_clear_pipeline(struct v3dv_device *device,
9257ec681f3Smrg                         VkImageAspectFlags aspects,
9267ec681f3Smrg                         struct v3dv_render_pass *pass,
9277ec681f3Smrg                         uint32_t subpass_idx,
9287ec681f3Smrg                         uint32_t attachment_idx,
9297ec681f3Smrg                         bool is_layered,
9307ec681f3Smrg                         struct v3dv_meta_depth_clear_pipeline **pipeline)
9317ec681f3Smrg{
9327ec681f3Smrg   assert(subpass_idx < pass->subpass_count);
9337ec681f3Smrg   assert(attachment_idx != VK_ATTACHMENT_UNUSED);
9347ec681f3Smrg   assert(attachment_idx < pass->attachment_count);
9357ec681f3Smrg
9367ec681f3Smrg   VkResult result = VK_SUCCESS;
9377ec681f3Smrg
9387ec681f3Smrg   const uint32_t samples = pass->attachments[attachment_idx].desc.samples;
9397ec681f3Smrg   const VkFormat format = pass->attachments[attachment_idx].desc.format;
9407ec681f3Smrg   assert(vk_format_is_depth_or_stencil(format));
9417ec681f3Smrg
9427ec681f3Smrg   const uint64_t key =
9437ec681f3Smrg      get_depth_clear_pipeline_cache_key(aspects, format, samples, is_layered);
9447ec681f3Smrg   mtx_lock(&device->meta.mtx);
9457ec681f3Smrg   struct hash_entry *entry =
9467ec681f3Smrg      _mesa_hash_table_search(device->meta.depth_clear.cache, &key);
9477ec681f3Smrg   if (entry) {
9487ec681f3Smrg      mtx_unlock(&device->meta.mtx);
9497ec681f3Smrg      *pipeline = entry->data;
9507ec681f3Smrg      return VK_SUCCESS;
9517ec681f3Smrg   }
9527ec681f3Smrg
9537ec681f3Smrg   *pipeline = vk_zalloc2(&device->vk.alloc, NULL, sizeof(**pipeline), 8,
9547ec681f3Smrg                          VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
9557ec681f3Smrg
9567ec681f3Smrg   if (*pipeline == NULL) {
9577ec681f3Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
9587ec681f3Smrg      goto fail;
9597ec681f3Smrg   }
9607ec681f3Smrg
9617ec681f3Smrg   result = create_depth_clear_pipeline(device,
9627ec681f3Smrg                                        aspects,
9637ec681f3Smrg                                        pass,
9647ec681f3Smrg                                        subpass_idx,
9657ec681f3Smrg                                        samples,
9667ec681f3Smrg                                        is_layered,
9677ec681f3Smrg                                        device->meta.depth_clear.p_layout,
9687ec681f3Smrg                                        &(*pipeline)->pipeline);
9697ec681f3Smrg   if (result != VK_SUCCESS)
9707ec681f3Smrg      goto fail;
9717ec681f3Smrg
9727ec681f3Smrg   (*pipeline)->key = key;
9737ec681f3Smrg   _mesa_hash_table_insert(device->meta.depth_clear.cache,
9747ec681f3Smrg                           &(*pipeline)->key, *pipeline);
9757ec681f3Smrg
9767ec681f3Smrg   mtx_unlock(&device->meta.mtx);
9777ec681f3Smrg   return VK_SUCCESS;
9787ec681f3Smrg
9797ec681f3Smrgfail:
9807ec681f3Smrg   mtx_unlock(&device->meta.mtx);
9817ec681f3Smrg
9827ec681f3Smrg   VkDevice _device = v3dv_device_to_handle(device);
9837ec681f3Smrg   if (*pipeline) {
9847ec681f3Smrg      if ((*pipeline)->pipeline)
9857ec681f3Smrg         v3dv_DestroyPipeline(_device, (*pipeline)->pipeline, &device->vk.alloc);
9867ec681f3Smrg      vk_free(&device->vk.alloc, *pipeline);
9877ec681f3Smrg      *pipeline = NULL;
9887ec681f3Smrg   }
9897ec681f3Smrg
9907ec681f3Smrg   return result;
9917ec681f3Smrg}
9927ec681f3Smrg
9937ec681f3Smrg/* Emits a scissored quad in the clear color */
9947ec681f3Smrgstatic void
9957ec681f3Smrgemit_subpass_color_clear_rects(struct v3dv_cmd_buffer *cmd_buffer,
9967ec681f3Smrg                               struct v3dv_render_pass *pass,
9977ec681f3Smrg                               struct v3dv_subpass *subpass,
9987ec681f3Smrg                               uint32_t rt_idx,
9997ec681f3Smrg                               const VkClearColorValue *clear_color,
10007ec681f3Smrg                               bool is_layered,
10017ec681f3Smrg                               bool all_rects_same_layers,
10027ec681f3Smrg                               uint32_t rect_count,
10037ec681f3Smrg                               const VkClearRect *rects)
10047ec681f3Smrg{
10057ec681f3Smrg   /* Skip if attachment is unused in the current subpass */
10067ec681f3Smrg   assert(rt_idx < subpass->color_count);
10077ec681f3Smrg   const uint32_t attachment_idx = subpass->color_attachments[rt_idx].attachment;
10087ec681f3Smrg   if (attachment_idx == VK_ATTACHMENT_UNUSED)
10097ec681f3Smrg      return;
10107ec681f3Smrg
10117ec681f3Smrg   /* Obtain a pipeline for this clear */
10127ec681f3Smrg   assert(attachment_idx < cmd_buffer->state.pass->attachment_count);
10137ec681f3Smrg   const VkFormat format =
10147ec681f3Smrg      cmd_buffer->state.pass->attachments[attachment_idx].desc.format;
10157ec681f3Smrg   const VkFormat samples =
10167ec681f3Smrg      cmd_buffer->state.pass->attachments[attachment_idx].desc.samples;
10177ec681f3Smrg   const uint32_t components = VK_COLOR_COMPONENT_R_BIT |
10187ec681f3Smrg                               VK_COLOR_COMPONENT_G_BIT |
10197ec681f3Smrg                               VK_COLOR_COMPONENT_B_BIT |
10207ec681f3Smrg                               VK_COLOR_COMPONENT_A_BIT;
10217ec681f3Smrg   struct v3dv_meta_color_clear_pipeline *pipeline = NULL;
10227ec681f3Smrg   VkResult result = get_color_clear_pipeline(cmd_buffer->device,
10237ec681f3Smrg                                              pass,
10247ec681f3Smrg                                              cmd_buffer->state.subpass_idx,
10257ec681f3Smrg                                              rt_idx,
10267ec681f3Smrg                                              attachment_idx,
10277ec681f3Smrg                                              format,
10287ec681f3Smrg                                              samples,
10297ec681f3Smrg                                              components,
10307ec681f3Smrg                                              is_layered,
10317ec681f3Smrg                                              &pipeline);
10327ec681f3Smrg   if (result != VK_SUCCESS) {
10337ec681f3Smrg      if (result == VK_ERROR_OUT_OF_HOST_MEMORY)
10347ec681f3Smrg         v3dv_flag_oom(cmd_buffer, NULL);
10357ec681f3Smrg      return;
10367ec681f3Smrg   }
10377ec681f3Smrg   assert(pipeline && pipeline->pipeline);
10387ec681f3Smrg
10397ec681f3Smrg   /* Emit clear rects */
10407ec681f3Smrg   v3dv_cmd_buffer_meta_state_push(cmd_buffer, false);
10417ec681f3Smrg
10427ec681f3Smrg   VkCommandBuffer cmd_buffer_handle = v3dv_cmd_buffer_to_handle(cmd_buffer);
10437ec681f3Smrg   v3dv_CmdPushConstants(cmd_buffer_handle,
10447ec681f3Smrg                         cmd_buffer->device->meta.depth_clear.p_layout,
10457ec681f3Smrg                         VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16,
10467ec681f3Smrg                         clear_color->float32);
10477ec681f3Smrg
10487ec681f3Smrg   v3dv_CmdBindPipeline(cmd_buffer_handle,
10497ec681f3Smrg                        VK_PIPELINE_BIND_POINT_GRAPHICS,
10507ec681f3Smrg                        pipeline->pipeline);
10517ec681f3Smrg
10527ec681f3Smrg   uint32_t dynamic_states = V3DV_CMD_DIRTY_VIEWPORT | V3DV_CMD_DIRTY_SCISSOR;
10537ec681f3Smrg
10547ec681f3Smrg   for (uint32_t i = 0; i < rect_count; i++) {
10557ec681f3Smrg      const VkViewport viewport = {
10567ec681f3Smrg         .x = rects[i].rect.offset.x,
10577ec681f3Smrg         .y = rects[i].rect.offset.y,
10587ec681f3Smrg         .width = rects[i].rect.extent.width,
10597ec681f3Smrg         .height = rects[i].rect.extent.height,
10607ec681f3Smrg         .minDepth = 0.0f,
10617ec681f3Smrg         .maxDepth = 1.0f
10627ec681f3Smrg      };
10637ec681f3Smrg      v3dv_CmdSetViewport(cmd_buffer_handle, 0, 1, &viewport);
10647ec681f3Smrg      v3dv_CmdSetScissor(cmd_buffer_handle, 0, 1, &rects[i].rect);
10657ec681f3Smrg
10667ec681f3Smrg      if (is_layered) {
10677ec681f3Smrg         for (uint32_t layer_offset = 0; layer_offset < rects[i].layerCount;
10687ec681f3Smrg              layer_offset++) {
10697ec681f3Smrg            uint32_t layer = rects[i].baseArrayLayer + layer_offset;
10707ec681f3Smrg            v3dv_CmdPushConstants(cmd_buffer_handle,
10717ec681f3Smrg                                  cmd_buffer->device->meta.depth_clear.p_layout,
10727ec681f3Smrg                                  VK_SHADER_STAGE_GEOMETRY_BIT, 16, 4, &layer);
10737ec681f3Smrg            v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
10747ec681f3Smrg         }
10757ec681f3Smrg      } else {
10767ec681f3Smrg         assert(rects[i].baseArrayLayer == 0 && rects[i].layerCount == 1);
10777ec681f3Smrg         v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
10787ec681f3Smrg      }
10797ec681f3Smrg   }
10807ec681f3Smrg
10817ec681f3Smrg   /* Subpass pipelines can't be cached because they include a reference to the
10827ec681f3Smrg    * render pass currently bound by the application, which means that we need
10837ec681f3Smrg    * to destroy them manually here.
10847ec681f3Smrg    */
10857ec681f3Smrg   assert(!pipeline->cached);
10867ec681f3Smrg   v3dv_cmd_buffer_add_private_obj(
10877ec681f3Smrg      cmd_buffer, (uintptr_t)pipeline,
10887ec681f3Smrg      (v3dv_cmd_buffer_private_obj_destroy_cb) destroy_color_clear_pipeline);
10897ec681f3Smrg
10907ec681f3Smrg   v3dv_cmd_buffer_meta_state_pop(cmd_buffer, dynamic_states, false);
10917ec681f3Smrg}
10927ec681f3Smrg
10937ec681f3Smrg/* Emits a scissored quad, clearing the depth aspect by writing to gl_FragDepth
10947ec681f3Smrg * and the stencil aspect by using stencil testing.
10957ec681f3Smrg */
10967ec681f3Smrgstatic void
10977ec681f3Smrgemit_subpass_ds_clear_rects(struct v3dv_cmd_buffer *cmd_buffer,
10987ec681f3Smrg                            struct v3dv_render_pass *pass,
10997ec681f3Smrg                            struct v3dv_subpass *subpass,
11007ec681f3Smrg                            VkImageAspectFlags aspects,
11017ec681f3Smrg                            const VkClearDepthStencilValue *clear_ds,
11027ec681f3Smrg                            bool is_layered,
11037ec681f3Smrg                            bool all_rects_same_layers,
11047ec681f3Smrg                            uint32_t rect_count,
11057ec681f3Smrg                            const VkClearRect *rects)
11067ec681f3Smrg{
11077ec681f3Smrg   /* Skip if attachment is unused in the current subpass */
11087ec681f3Smrg   const uint32_t attachment_idx = subpass->ds_attachment.attachment;
11097ec681f3Smrg   if (attachment_idx == VK_ATTACHMENT_UNUSED)
11107ec681f3Smrg      return;
11117ec681f3Smrg
11127ec681f3Smrg   /* Obtain a pipeline for this clear */
11137ec681f3Smrg   assert(attachment_idx < cmd_buffer->state.pass->attachment_count);
11147ec681f3Smrg   struct v3dv_meta_depth_clear_pipeline *pipeline = NULL;
11157ec681f3Smrg   VkResult result = get_depth_clear_pipeline(cmd_buffer->device,
11167ec681f3Smrg                                              aspects,
11177ec681f3Smrg                                              pass,
11187ec681f3Smrg                                              cmd_buffer->state.subpass_idx,
11197ec681f3Smrg                                              attachment_idx,
11207ec681f3Smrg                                              is_layered,
11217ec681f3Smrg                                              &pipeline);
11227ec681f3Smrg   if (result != VK_SUCCESS) {
11237ec681f3Smrg      if (result == VK_ERROR_OUT_OF_HOST_MEMORY)
11247ec681f3Smrg         v3dv_flag_oom(cmd_buffer, NULL);
11257ec681f3Smrg      return;
11267ec681f3Smrg   }
11277ec681f3Smrg   assert(pipeline && pipeline->pipeline);
11287ec681f3Smrg
11297ec681f3Smrg   /* Emit clear rects */
11307ec681f3Smrg   v3dv_cmd_buffer_meta_state_push(cmd_buffer, false);
11317ec681f3Smrg
11327ec681f3Smrg   VkCommandBuffer cmd_buffer_handle = v3dv_cmd_buffer_to_handle(cmd_buffer);
11337ec681f3Smrg   v3dv_CmdPushConstants(cmd_buffer_handle,
11347ec681f3Smrg                         cmd_buffer->device->meta.depth_clear.p_layout,
11357ec681f3Smrg                         VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4,
11367ec681f3Smrg                         &clear_ds->depth);
11377ec681f3Smrg
11387ec681f3Smrg   v3dv_CmdBindPipeline(cmd_buffer_handle,
11397ec681f3Smrg                        VK_PIPELINE_BIND_POINT_GRAPHICS,
11407ec681f3Smrg                        pipeline->pipeline);
11417ec681f3Smrg
11427ec681f3Smrg   uint32_t dynamic_states = V3DV_CMD_DIRTY_VIEWPORT | V3DV_CMD_DIRTY_SCISSOR;
11437ec681f3Smrg   if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
11447ec681f3Smrg      v3dv_CmdSetStencilReference(cmd_buffer_handle,
11457ec681f3Smrg                                  VK_STENCIL_FACE_FRONT_AND_BACK,
11467ec681f3Smrg                                  clear_ds->stencil);
11477ec681f3Smrg      v3dv_CmdSetStencilWriteMask(cmd_buffer_handle,
11487ec681f3Smrg                                  VK_STENCIL_FACE_FRONT_AND_BACK, 0xff);
11497ec681f3Smrg      v3dv_CmdSetStencilCompareMask(cmd_buffer_handle,
11507ec681f3Smrg                                    VK_STENCIL_FACE_FRONT_AND_BACK, 0xff);
11517ec681f3Smrg      dynamic_states |= VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK |
11527ec681f3Smrg                        VK_DYNAMIC_STATE_STENCIL_WRITE_MASK |
11537ec681f3Smrg                        VK_DYNAMIC_STATE_STENCIL_REFERENCE;
11547ec681f3Smrg   }
11557ec681f3Smrg
11567ec681f3Smrg   for (uint32_t i = 0; i < rect_count; i++) {
11577ec681f3Smrg      const VkViewport viewport = {
11587ec681f3Smrg         .x = rects[i].rect.offset.x,
11597ec681f3Smrg         .y = rects[i].rect.offset.y,
11607ec681f3Smrg         .width = rects[i].rect.extent.width,
11617ec681f3Smrg         .height = rects[i].rect.extent.height,
11627ec681f3Smrg         .minDepth = 0.0f,
11637ec681f3Smrg         .maxDepth = 1.0f
11647ec681f3Smrg      };
11657ec681f3Smrg      v3dv_CmdSetViewport(cmd_buffer_handle, 0, 1, &viewport);
11667ec681f3Smrg      v3dv_CmdSetScissor(cmd_buffer_handle, 0, 1, &rects[i].rect);
11677ec681f3Smrg      if (is_layered) {
11687ec681f3Smrg         for (uint32_t layer_offset = 0; layer_offset < rects[i].layerCount;
11697ec681f3Smrg              layer_offset++) {
11707ec681f3Smrg            uint32_t layer = rects[i].baseArrayLayer + layer_offset;
11717ec681f3Smrg            v3dv_CmdPushConstants(cmd_buffer_handle,
11727ec681f3Smrg                                  cmd_buffer->device->meta.depth_clear.p_layout,
11737ec681f3Smrg                                  VK_SHADER_STAGE_GEOMETRY_BIT, 4, 4, &layer);
11747ec681f3Smrg            v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
11757ec681f3Smrg         }
11767ec681f3Smrg      } else {
11777ec681f3Smrg         assert(rects[i].baseArrayLayer == 0 && rects[i].layerCount == 1);
11787ec681f3Smrg         v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
11797ec681f3Smrg      }
11807ec681f3Smrg   }
11817ec681f3Smrg
11827ec681f3Smrg   v3dv_cmd_buffer_meta_state_pop(cmd_buffer, dynamic_states, false);
11837ec681f3Smrg}
11847ec681f3Smrg
11857ec681f3Smrgstatic void
11867ec681f3Smrggather_layering_info(uint32_t rect_count, const VkClearRect *rects,
11877ec681f3Smrg                     bool *is_layered, bool *all_rects_same_layers)
11887ec681f3Smrg{
11897ec681f3Smrg   *all_rects_same_layers = true;
11907ec681f3Smrg
11917ec681f3Smrg   uint32_t min_layer = rects[0].baseArrayLayer;
11927ec681f3Smrg   uint32_t max_layer = rects[0].baseArrayLayer + rects[0].layerCount - 1;
11937ec681f3Smrg   for (uint32_t i = 1; i < rect_count; i++) {
11947ec681f3Smrg      if (rects[i].baseArrayLayer != rects[i - 1].baseArrayLayer ||
11957ec681f3Smrg          rects[i].layerCount != rects[i - 1].layerCount) {
11967ec681f3Smrg         *all_rects_same_layers = false;
11977ec681f3Smrg         min_layer = MIN2(min_layer, rects[i].baseArrayLayer);
11987ec681f3Smrg         max_layer = MAX2(max_layer, rects[i].baseArrayLayer +
11997ec681f3Smrg                                     rects[i].layerCount - 1);
12007ec681f3Smrg      }
12017ec681f3Smrg   }
12027ec681f3Smrg
12037ec681f3Smrg   *is_layered = !(min_layer == 0 && max_layer == 0);
12047ec681f3Smrg}
12057ec681f3Smrg
12067ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
12077ec681f3Smrgv3dv_CmdClearAttachments(VkCommandBuffer commandBuffer,
12087ec681f3Smrg                         uint32_t attachmentCount,
12097ec681f3Smrg                         const VkClearAttachment *pAttachments,
12107ec681f3Smrg                         uint32_t rectCount,
12117ec681f3Smrg                         const VkClearRect *pRects)
12127ec681f3Smrg{
12137ec681f3Smrg   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
12147ec681f3Smrg
12157ec681f3Smrg   /* We can only clear attachments in the current subpass */
12167ec681f3Smrg   assert(attachmentCount <= 5); /* 4 color + D/S */
12177ec681f3Smrg
12187ec681f3Smrg   struct v3dv_render_pass *pass = cmd_buffer->state.pass;
12197ec681f3Smrg
12207ec681f3Smrg   assert(cmd_buffer->state.subpass_idx < pass->subpass_count);
12217ec681f3Smrg   struct v3dv_subpass *subpass =
12227ec681f3Smrg      &cmd_buffer->state.pass->subpasses[cmd_buffer->state.subpass_idx];
12237ec681f3Smrg
12247ec681f3Smrg   /* Emit a clear rect inside the current job for this subpass. For layered
12257ec681f3Smrg    * framebuffers, we use a geometry shader to redirect clears to the
12267ec681f3Smrg    * appropriate layers.
12277ec681f3Smrg    */
12287ec681f3Smrg   bool is_layered, all_rects_same_layers;
12297ec681f3Smrg   gather_layering_info(rectCount, pRects, &is_layered, &all_rects_same_layers);
12307ec681f3Smrg   for (uint32_t i = 0; i < attachmentCount; i++) {
12317ec681f3Smrg      if (pAttachments[i].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
12327ec681f3Smrg         emit_subpass_color_clear_rects(cmd_buffer, pass, subpass,
12337ec681f3Smrg                                        pAttachments[i].colorAttachment,
12347ec681f3Smrg                                        &pAttachments[i].clearValue.color,
12357ec681f3Smrg                                        is_layered, all_rects_same_layers,
12367ec681f3Smrg                                        rectCount, pRects);
12377ec681f3Smrg      } else {
12387ec681f3Smrg         emit_subpass_ds_clear_rects(cmd_buffer, pass, subpass,
12397ec681f3Smrg                                     pAttachments[i].aspectMask,
12407ec681f3Smrg                                     &pAttachments[i].clearValue.depthStencil,
12417ec681f3Smrg                                     is_layered, all_rects_same_layers,
12427ec681f3Smrg                                     rectCount, pRects);
12437ec681f3Smrg      }
12447ec681f3Smrg   }
12457ec681f3Smrg}
1246