1/*
2 * Copyright © 2020 Raspberry Pi Ltd
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include "v3dv_private.h"
25#include "v3dv_meta_common.h"
26
27#include "compiler/nir/nir_builder.h"
28#include "util/u_pack_color.h"
29
30static void
31get_hw_clear_color(struct v3dv_device *device,
32                   const VkClearColorValue *color,
33                   VkFormat fb_format,
34                   VkFormat image_format,
35                   uint32_t internal_type,
36                   uint32_t internal_bpp,
37                   uint32_t *hw_color)
38{
39   const uint32_t internal_size = 4 << internal_bpp;
40
41   /* If the image format doesn't match the framebuffer format, then we are
42    * trying to clear an unsupported tlb format using a compatible
43    * format for the framebuffer. In this case, we want to make sure that
44    * we pack the clear value according to the original format semantics,
45    * not the compatible format.
46    */
47   if (fb_format == image_format) {
48      v3dv_X(device, get_hw_clear_color)(color, internal_type, internal_size,
49                                         hw_color);
50   } else {
51      union util_color uc;
52      enum pipe_format pipe_image_format =
53         vk_format_to_pipe_format(image_format);
54      util_pack_color(color->float32, pipe_image_format, &uc);
55      memcpy(hw_color, uc.ui, internal_size);
56   }
57}
58
59/* Returns true if the implementation is able to handle the case, false
60 * otherwise.
61*/
62static bool
63clear_image_tlb(struct v3dv_cmd_buffer *cmd_buffer,
64                struct v3dv_image *image,
65                const VkClearValue *clear_value,
66                const VkImageSubresourceRange *range)
67{
68   const VkOffset3D origin = { 0, 0, 0 };
69   VkFormat fb_format;
70   if (!v3dv_meta_can_use_tlb(image, &origin, &fb_format))
71      return false;
72
73   uint32_t internal_type, internal_bpp;
74   v3dv_X(cmd_buffer->device, get_internal_type_bpp_for_image_aspects)
75      (fb_format, range->aspectMask,
76       &internal_type, &internal_bpp);
77
78   union v3dv_clear_value hw_clear_value = { 0 };
79   if (range->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
80      get_hw_clear_color(cmd_buffer->device, &clear_value->color, fb_format,
81                         image->vk.format, internal_type, internal_bpp,
82                         &hw_clear_value.color[0]);
83   } else {
84      assert((range->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
85             (range->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT));
86      hw_clear_value.z = clear_value->depthStencil.depth;
87      hw_clear_value.s = clear_value->depthStencil.stencil;
88   }
89
90   uint32_t level_count = vk_image_subresource_level_count(&image->vk, range);
91   uint32_t min_level = range->baseMipLevel;
92   uint32_t max_level = range->baseMipLevel + level_count;
93
94   /* For 3D images baseArrayLayer and layerCount must be 0 and 1 respectively.
95    * Instead, we need to consider the full depth dimension of the image, which
96    * goes from 0 up to the level's depth extent.
97    */
98   uint32_t min_layer;
99   uint32_t max_layer;
100   if (image->vk.image_type != VK_IMAGE_TYPE_3D) {
101      min_layer = range->baseArrayLayer;
102      max_layer = range->baseArrayLayer +
103                  vk_image_subresource_layer_count(&image->vk, range);
104   } else {
105      min_layer = 0;
106      max_layer = 0;
107   }
108
109   for (uint32_t level = min_level; level < max_level; level++) {
110      if (image->vk.image_type == VK_IMAGE_TYPE_3D)
111         max_layer = u_minify(image->vk.extent.depth, level);
112
113      uint32_t width = u_minify(image->vk.extent.width, level);
114      uint32_t height = u_minify(image->vk.extent.height, level);
115
116      struct v3dv_job *job =
117         v3dv_cmd_buffer_start_job(cmd_buffer, -1, V3DV_JOB_TYPE_GPU_CL);
118
119      if (!job)
120         return true;
121
122      v3dv_job_start_frame(job, width, height, max_layer, false,
123                           1, internal_bpp,
124                           image->vk.samples > VK_SAMPLE_COUNT_1_BIT);
125
126      struct v3dv_meta_framebuffer framebuffer;
127      v3dv_X(job->device, meta_framebuffer_init)(&framebuffer, fb_format,
128                                                 internal_type,
129                                                 &job->frame_tiling);
130
131      v3dv_X(job->device, job_emit_binning_flush)(job);
132
133      /* If this triggers it is an application bug: the spec requires
134       * that any aspects to clear are present in the image.
135       */
136      assert(range->aspectMask & image->vk.aspects);
137
138      v3dv_X(job->device, meta_emit_clear_image_rcl)
139         (job, image, &framebuffer, &hw_clear_value,
140          range->aspectMask, min_layer, max_layer, level);
141
142      v3dv_cmd_buffer_finish_job(cmd_buffer);
143   }
144
145   return true;
146}
147
148VKAPI_ATTR void VKAPI_CALL
149v3dv_CmdClearColorImage(VkCommandBuffer commandBuffer,
150                        VkImage _image,
151                        VkImageLayout imageLayout,
152                        const VkClearColorValue *pColor,
153                        uint32_t rangeCount,
154                        const VkImageSubresourceRange *pRanges)
155{
156   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
157   V3DV_FROM_HANDLE(v3dv_image, image, _image);
158
159   const VkClearValue clear_value = {
160      .color = *pColor,
161   };
162
163   cmd_buffer->state.is_transfer = true;
164
165   for (uint32_t i = 0; i < rangeCount; i++) {
166      if (clear_image_tlb(cmd_buffer, image, &clear_value, &pRanges[i]))
167         continue;
168      unreachable("Unsupported color clear.");
169   }
170
171   cmd_buffer->state.is_transfer = false;
172}
173
174VKAPI_ATTR void VKAPI_CALL
175v3dv_CmdClearDepthStencilImage(VkCommandBuffer commandBuffer,
176                               VkImage _image,
177                               VkImageLayout imageLayout,
178                               const VkClearDepthStencilValue *pDepthStencil,
179                               uint32_t rangeCount,
180                               const VkImageSubresourceRange *pRanges)
181{
182   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
183   V3DV_FROM_HANDLE(v3dv_image, image, _image);
184
185   const VkClearValue clear_value = {
186      .depthStencil = *pDepthStencil,
187   };
188
189   cmd_buffer->state.is_transfer = true;
190
191   for (uint32_t i = 0; i < rangeCount; i++) {
192      if (clear_image_tlb(cmd_buffer, image, &clear_value, &pRanges[i]))
193         continue;
194      unreachable("Unsupported depth/stencil clear.");
195   }
196
197   cmd_buffer->state.is_transfer = false;
198}
199
200static void
201destroy_color_clear_pipeline(VkDevice _device,
202                             uint64_t pipeline,
203                             VkAllocationCallbacks *alloc)
204{
205   struct v3dv_meta_color_clear_pipeline *p =
206      (struct v3dv_meta_color_clear_pipeline *) (uintptr_t) pipeline;
207   v3dv_DestroyPipeline(_device, p->pipeline, alloc);
208   if (p->cached)
209      v3dv_DestroyRenderPass(_device, p->pass, alloc);
210   vk_free(alloc, p);
211}
212
213static void
214destroy_depth_clear_pipeline(VkDevice _device,
215                             struct v3dv_meta_depth_clear_pipeline *p,
216                             VkAllocationCallbacks *alloc)
217{
218   v3dv_DestroyPipeline(_device, p->pipeline, alloc);
219   vk_free(alloc, p);
220}
221
222static VkResult
223create_color_clear_pipeline_layout(struct v3dv_device *device,
224                                   VkPipelineLayout *pipeline_layout)
225{
226   /* FIXME: this is abusing a bit the API, since not all of our clear
227    * pipelines have a geometry shader. We could create 2 different pipeline
228    * layouts, but this works for us for now.
229    */
230   VkPushConstantRange ranges[2] = {
231      { VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16 },
232      { VK_SHADER_STAGE_GEOMETRY_BIT, 16, 4 },
233   };
234
235   VkPipelineLayoutCreateInfo info = {
236      .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
237      .setLayoutCount = 0,
238      .pushConstantRangeCount = 2,
239      .pPushConstantRanges = ranges,
240   };
241
242   return v3dv_CreatePipelineLayout(v3dv_device_to_handle(device),
243                                    &info, &device->vk.alloc, pipeline_layout);
244}
245
246static VkResult
247create_depth_clear_pipeline_layout(struct v3dv_device *device,
248                                   VkPipelineLayout *pipeline_layout)
249{
250   /* FIXME: this is abusing a bit the API, since not all of our clear
251    * pipelines have a geometry shader. We could create 2 different pipeline
252    * layouts, but this works for us for now.
253    */
254   VkPushConstantRange ranges[2] = {
255      { VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4 },
256      { VK_SHADER_STAGE_GEOMETRY_BIT, 4, 4 },
257   };
258
259   VkPipelineLayoutCreateInfo info = {
260      .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
261      .setLayoutCount = 0,
262      .pushConstantRangeCount = 2,
263      .pPushConstantRanges = ranges
264   };
265
266   return v3dv_CreatePipelineLayout(v3dv_device_to_handle(device),
267                                    &info, &device->vk.alloc, pipeline_layout);
268}
269
270void
271v3dv_meta_clear_init(struct v3dv_device *device)
272{
273   device->meta.color_clear.cache =
274      _mesa_hash_table_create(NULL, u64_hash, u64_compare);
275
276   create_color_clear_pipeline_layout(device,
277                                      &device->meta.color_clear.p_layout);
278
279   device->meta.depth_clear.cache =
280      _mesa_hash_table_create(NULL, u64_hash, u64_compare);
281
282   create_depth_clear_pipeline_layout(device,
283                                      &device->meta.depth_clear.p_layout);
284}
285
286void
287v3dv_meta_clear_finish(struct v3dv_device *device)
288{
289   VkDevice _device = v3dv_device_to_handle(device);
290
291   hash_table_foreach(device->meta.color_clear.cache, entry) {
292      struct v3dv_meta_color_clear_pipeline *item = entry->data;
293      destroy_color_clear_pipeline(_device, (uintptr_t)item, &device->vk.alloc);
294   }
295   _mesa_hash_table_destroy(device->meta.color_clear.cache, NULL);
296
297   if (device->meta.color_clear.p_layout) {
298      v3dv_DestroyPipelineLayout(_device, device->meta.color_clear.p_layout,
299                                 &device->vk.alloc);
300   }
301
302   hash_table_foreach(device->meta.depth_clear.cache, entry) {
303      struct v3dv_meta_depth_clear_pipeline *item = entry->data;
304      destroy_depth_clear_pipeline(_device, item, &device->vk.alloc);
305   }
306   _mesa_hash_table_destroy(device->meta.depth_clear.cache, NULL);
307
308   if (device->meta.depth_clear.p_layout) {
309      v3dv_DestroyPipelineLayout(_device, device->meta.depth_clear.p_layout,
310                                 &device->vk.alloc);
311   }
312}
313
314static nir_shader *
315get_clear_rect_vs()
316{
317   const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
318   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, options,
319                                                  "meta clear vs");
320
321   const struct glsl_type *vec4 = glsl_vec4_type();
322   nir_variable *vs_out_pos =
323      nir_variable_create(b.shader, nir_var_shader_out, vec4, "gl_Position");
324   vs_out_pos->data.location = VARYING_SLOT_POS;
325
326   nir_ssa_def *pos = nir_gen_rect_vertices(&b, NULL, NULL);
327   nir_store_var(&b, vs_out_pos, pos, 0xf);
328
329   return b.shader;
330}
331
332static nir_shader *
333get_clear_rect_gs(uint32_t push_constant_layer_base)
334{
335   /* FIXME: this creates a geometry shader that takes the index of a single
336    * layer to clear from push constants, so we need to emit a draw call for
337    * each layer that we want to clear. We could actually do better and have it
338    * take a range of layers and then emit one triangle per layer to clear,
339    * however, if we were to do this we would need to be careful not to exceed
340    * the maximum number of output vertices allowed in a geometry shader.
341    */
342   const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
343   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, options,
344                                                  "meta clear gs");
345   nir_shader *nir = b.shader;
346   nir->info.inputs_read = 1ull << VARYING_SLOT_POS;
347   nir->info.outputs_written = (1ull << VARYING_SLOT_POS) |
348                               (1ull << VARYING_SLOT_LAYER);
349   nir->info.gs.input_primitive = SHADER_PRIM_TRIANGLES;
350   nir->info.gs.output_primitive = SHADER_PRIM_TRIANGLE_STRIP;
351   nir->info.gs.vertices_in = 3;
352   nir->info.gs.vertices_out = 3;
353   nir->info.gs.invocations = 1;
354   nir->info.gs.active_stream_mask = 0x1;
355
356   /* in vec4 gl_Position[3] */
357   nir_variable *gs_in_pos =
358      nir_variable_create(b.shader, nir_var_shader_in,
359                          glsl_array_type(glsl_vec4_type(), 3, 0),
360                          "in_gl_Position");
361   gs_in_pos->data.location = VARYING_SLOT_POS;
362
363   /* out vec4 gl_Position */
364   nir_variable *gs_out_pos =
365      nir_variable_create(b.shader, nir_var_shader_out, glsl_vec4_type(),
366                          "out_gl_Position");
367   gs_out_pos->data.location = VARYING_SLOT_POS;
368
369   /* out float gl_Layer */
370   nir_variable *gs_out_layer =
371      nir_variable_create(b.shader, nir_var_shader_out, glsl_float_type(),
372                          "out_gl_Layer");
373   gs_out_layer->data.location = VARYING_SLOT_LAYER;
374
375   /* Emit output triangle */
376   for (uint32_t i = 0; i < 3; i++) {
377      /* gl_Position from shader input */
378      nir_deref_instr *in_pos_i =
379         nir_build_deref_array_imm(&b, nir_build_deref_var(&b, gs_in_pos), i);
380      nir_copy_deref(&b, nir_build_deref_var(&b, gs_out_pos), in_pos_i);
381
382      /* gl_Layer from push constants */
383      nir_ssa_def *layer =
384         nir_load_push_constant(&b, 1, 32, nir_imm_int(&b, 0),
385                                .base = push_constant_layer_base, .range = 4);
386      nir_store_var(&b, gs_out_layer, layer, 0x1);
387
388      nir_emit_vertex(&b, 0);
389   }
390
391   nir_end_primitive(&b, 0);
392
393   return nir;
394}
395
396static nir_shader *
397get_color_clear_rect_fs(uint32_t rt_idx, VkFormat format)
398{
399   const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
400   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, options,
401                                                  "meta clear fs");
402
403   enum pipe_format pformat = vk_format_to_pipe_format(format);
404   const struct glsl_type *fs_out_type =
405      util_format_is_float(pformat) ? glsl_vec4_type() : glsl_uvec4_type();
406
407   nir_variable *fs_out_color =
408      nir_variable_create(b.shader, nir_var_shader_out, fs_out_type, "out_color");
409   fs_out_color->data.location = FRAG_RESULT_DATA0 + rt_idx;
410
411   nir_ssa_def *color_load = nir_load_push_constant(&b, 4, 32, nir_imm_int(&b, 0), .base = 0, .range = 16);
412   nir_store_var(&b, fs_out_color, color_load, 0xf);
413
414   return b.shader;
415}
416
417static nir_shader *
418get_depth_clear_rect_fs()
419{
420   const nir_shader_compiler_options *options = v3dv_pipeline_get_nir_options();
421   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, options,
422                                                  "meta depth clear fs");
423
424   nir_variable *fs_out_depth =
425      nir_variable_create(b.shader, nir_var_shader_out, glsl_float_type(),
426                          "out_depth");
427   fs_out_depth->data.location = FRAG_RESULT_DEPTH;
428
429   nir_ssa_def *depth_load =
430      nir_load_push_constant(&b, 1, 32, nir_imm_int(&b, 0), .base = 0, .range = 4);
431
432   nir_store_var(&b, fs_out_depth, depth_load, 0x1);
433
434   return b.shader;
435}
436
437static VkResult
438create_pipeline(struct v3dv_device *device,
439                struct v3dv_render_pass *pass,
440                uint32_t subpass_idx,
441                uint32_t samples,
442                struct nir_shader *vs_nir,
443                struct nir_shader *gs_nir,
444                struct nir_shader *fs_nir,
445                const VkPipelineVertexInputStateCreateInfo *vi_state,
446                const VkPipelineDepthStencilStateCreateInfo *ds_state,
447                const VkPipelineColorBlendStateCreateInfo *cb_state,
448                const VkPipelineLayout layout,
449                VkPipeline *pipeline)
450{
451   VkPipelineShaderStageCreateInfo stages[3] = { 0 };
452   struct vk_shader_module vs_m = vk_shader_module_from_nir(vs_nir);
453   struct vk_shader_module gs_m;
454   struct vk_shader_module fs_m;
455
456   uint32_t stage_count = 0;
457   stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
458   stages[stage_count].stage = VK_SHADER_STAGE_VERTEX_BIT;
459   stages[stage_count].module = vk_shader_module_to_handle(&vs_m);
460   stages[stage_count].pName = "main";
461   stage_count++;
462
463   if (gs_nir) {
464      gs_m = vk_shader_module_from_nir(gs_nir);
465      stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
466      stages[stage_count].stage = VK_SHADER_STAGE_GEOMETRY_BIT;
467      stages[stage_count].module = vk_shader_module_to_handle(&gs_m);
468      stages[stage_count].pName = "main";
469      stage_count++;
470   }
471
472   if (fs_nir) {
473      fs_m = vk_shader_module_from_nir(fs_nir);
474      stages[stage_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
475      stages[stage_count].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
476      stages[stage_count].module = vk_shader_module_to_handle(&fs_m);
477      stages[stage_count].pName = "main";
478      stage_count++;
479   }
480
481   VkGraphicsPipelineCreateInfo info = {
482      .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
483
484      .stageCount = stage_count,
485      .pStages = stages,
486
487      .pVertexInputState = vi_state,
488
489      .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
490         .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
491         .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
492         .primitiveRestartEnable = false,
493      },
494
495      .pViewportState = &(VkPipelineViewportStateCreateInfo) {
496         .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
497         .viewportCount = 1,
498         .scissorCount = 1,
499      },
500
501      .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
502         .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
503         .rasterizerDiscardEnable = false,
504         .polygonMode = VK_POLYGON_MODE_FILL,
505         .cullMode = VK_CULL_MODE_NONE,
506         .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
507         .depthBiasEnable = false,
508      },
509
510      .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
511         .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
512         .rasterizationSamples = samples,
513         .sampleShadingEnable = false,
514         .pSampleMask = NULL,
515         .alphaToCoverageEnable = false,
516         .alphaToOneEnable = false,
517      },
518
519      .pDepthStencilState = ds_state,
520
521      .pColorBlendState = cb_state,
522
523      /* The meta clear pipeline declares all state as dynamic.
524       * As a consequence, vkCmdBindPipeline writes no dynamic state
525       * to the cmd buffer. Therefore, at the end of the meta clear,
526       * we need only restore dynamic state that was vkCmdSet.
527       */
528      .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
529         .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
530         .dynamicStateCount = 6,
531         .pDynamicStates = (VkDynamicState[]) {
532            VK_DYNAMIC_STATE_VIEWPORT,
533            VK_DYNAMIC_STATE_SCISSOR,
534            VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
535            VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
536            VK_DYNAMIC_STATE_STENCIL_REFERENCE,
537            VK_DYNAMIC_STATE_BLEND_CONSTANTS,
538            VK_DYNAMIC_STATE_DEPTH_BIAS,
539            VK_DYNAMIC_STATE_LINE_WIDTH,
540         },
541      },
542
543      .flags = 0,
544      .layout = layout,
545      .renderPass = v3dv_render_pass_to_handle(pass),
546      .subpass = subpass_idx,
547   };
548
549   VkResult result =
550      v3dv_CreateGraphicsPipelines(v3dv_device_to_handle(device),
551                                   VK_NULL_HANDLE,
552                                   1, &info,
553                                   &device->vk.alloc,
554                                   pipeline);
555
556   ralloc_free(vs_nir);
557   ralloc_free(gs_nir);
558   ralloc_free(fs_nir);
559
560   return result;
561}
562
563static VkResult
564create_color_clear_pipeline(struct v3dv_device *device,
565                            struct v3dv_render_pass *pass,
566                            uint32_t subpass_idx,
567                            uint32_t rt_idx,
568                            VkFormat format,
569                            uint32_t samples,
570                            uint32_t components,
571                            bool is_layered,
572                            VkPipelineLayout pipeline_layout,
573                            VkPipeline *pipeline)
574{
575   nir_shader *vs_nir = get_clear_rect_vs();
576   nir_shader *fs_nir = get_color_clear_rect_fs(rt_idx, format);
577   nir_shader *gs_nir = is_layered ? get_clear_rect_gs(16) : NULL;
578
579   const VkPipelineVertexInputStateCreateInfo vi_state = {
580      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
581      .vertexBindingDescriptionCount = 0,
582      .vertexAttributeDescriptionCount = 0,
583   };
584
585   const VkPipelineDepthStencilStateCreateInfo ds_state = {
586      .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
587      .depthTestEnable = false,
588      .depthWriteEnable = false,
589      .depthBoundsTestEnable = false,
590      .stencilTestEnable = false,
591   };
592
593   assert(subpass_idx < pass->subpass_count);
594   const uint32_t color_count = pass->subpasses[subpass_idx].color_count;
595   assert(rt_idx < color_count);
596
597   VkPipelineColorBlendAttachmentState blend_att_state[V3D_MAX_DRAW_BUFFERS];
598   for (uint32_t i = 0; i < color_count; i++) {
599      blend_att_state[i] = (VkPipelineColorBlendAttachmentState) {
600         .blendEnable = false,
601         .colorWriteMask = i == rt_idx ? components : 0,
602      };
603   }
604
605   const VkPipelineColorBlendStateCreateInfo cb_state = {
606      .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
607      .logicOpEnable = false,
608      .attachmentCount = color_count,
609      .pAttachments = blend_att_state
610   };
611
612   return create_pipeline(device,
613                          pass, subpass_idx,
614                          samples,
615                          vs_nir, gs_nir, fs_nir,
616                          &vi_state,
617                          &ds_state,
618                          &cb_state,
619                          pipeline_layout,
620                          pipeline);
621}
622
623static VkResult
624create_depth_clear_pipeline(struct v3dv_device *device,
625                            VkImageAspectFlags aspects,
626                            struct v3dv_render_pass *pass,
627                            uint32_t subpass_idx,
628                            uint32_t samples,
629                            bool is_layered,
630                            VkPipelineLayout pipeline_layout,
631                            VkPipeline *pipeline)
632{
633   const bool has_depth = aspects & VK_IMAGE_ASPECT_DEPTH_BIT;
634   const bool has_stencil = aspects & VK_IMAGE_ASPECT_STENCIL_BIT;
635   assert(has_depth || has_stencil);
636
637   nir_shader *vs_nir = get_clear_rect_vs();
638   nir_shader *fs_nir = has_depth ? get_depth_clear_rect_fs() : NULL;
639   nir_shader *gs_nir = is_layered ? get_clear_rect_gs(4) : NULL;
640
641   const VkPipelineVertexInputStateCreateInfo vi_state = {
642      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
643      .vertexBindingDescriptionCount = 0,
644      .vertexAttributeDescriptionCount = 0,
645   };
646
647   const VkPipelineDepthStencilStateCreateInfo ds_state = {
648      .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
649      .depthTestEnable = has_depth,
650      .depthWriteEnable = has_depth,
651      .depthCompareOp = VK_COMPARE_OP_ALWAYS,
652      .depthBoundsTestEnable = false,
653      .stencilTestEnable = has_stencil,
654      .front = {
655         .passOp = VK_STENCIL_OP_REPLACE,
656         .compareOp = VK_COMPARE_OP_ALWAYS,
657         /* compareMask, writeMask and reference are dynamic state */
658      },
659      .back = { 0 },
660   };
661
662   assert(subpass_idx < pass->subpass_count);
663   VkPipelineColorBlendAttachmentState blend_att_state[V3D_MAX_DRAW_BUFFERS] = { 0 };
664   const VkPipelineColorBlendStateCreateInfo cb_state = {
665      .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
666      .logicOpEnable = false,
667      .attachmentCount = pass->subpasses[subpass_idx].color_count,
668      .pAttachments = blend_att_state,
669   };
670
671   return create_pipeline(device,
672                          pass, subpass_idx,
673                          samples,
674                          vs_nir, gs_nir, fs_nir,
675                          &vi_state,
676                          &ds_state,
677                          &cb_state,
678                          pipeline_layout,
679                          pipeline);
680}
681
682static VkResult
683create_color_clear_render_pass(struct v3dv_device *device,
684                               uint32_t rt_idx,
685                               VkFormat format,
686                               uint32_t samples,
687                               VkRenderPass *pass)
688{
689   VkAttachmentDescription2 att = {
690      .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,
691      .format = format,
692      .samples = samples,
693      .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
694      .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
695      .initialLayout = VK_IMAGE_LAYOUT_GENERAL,
696      .finalLayout = VK_IMAGE_LAYOUT_GENERAL,
697   };
698
699   VkAttachmentReference2 att_ref = {
700      .sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
701      .attachment = rt_idx,
702      .layout = VK_IMAGE_LAYOUT_GENERAL,
703   };
704
705   VkSubpassDescription2 subpass = {
706      .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2,
707      .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
708      .inputAttachmentCount = 0,
709      .colorAttachmentCount = 1,
710      .pColorAttachments = &att_ref,
711      .pResolveAttachments = NULL,
712      .pDepthStencilAttachment = NULL,
713      .preserveAttachmentCount = 0,
714      .pPreserveAttachments = NULL,
715   };
716
717   VkRenderPassCreateInfo2 info = {
718      .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2,
719      .attachmentCount = 1,
720      .pAttachments = &att,
721      .subpassCount = 1,
722      .pSubpasses = &subpass,
723      .dependencyCount = 0,
724      .pDependencies = NULL,
725   };
726
727   return v3dv_CreateRenderPass2(v3dv_device_to_handle(device),
728                                 &info, &device->vk.alloc, pass);
729}
730
731static inline uint64_t
732get_color_clear_pipeline_cache_key(uint32_t rt_idx,
733                                   VkFormat format,
734                                   uint32_t samples,
735                                   uint32_t components,
736                                   bool is_layered)
737{
738   assert(rt_idx < V3D_MAX_DRAW_BUFFERS);
739
740   uint64_t key = 0;
741   uint32_t bit_offset = 0;
742
743   key |= rt_idx;
744   bit_offset += 2;
745
746   key |= ((uint64_t) format) << bit_offset;
747   bit_offset += 32;
748
749   key |= ((uint64_t) samples) << bit_offset;
750   bit_offset += 4;
751
752   key |= ((uint64_t) components) << bit_offset;
753   bit_offset += 4;
754
755   key |= (is_layered ? 1ull : 0ull) << bit_offset;
756   bit_offset += 1;
757
758   assert(bit_offset <= 64);
759   return key;
760}
761
762static inline uint64_t
763get_depth_clear_pipeline_cache_key(VkImageAspectFlags aspects,
764                                   VkFormat format,
765                                   uint32_t samples,
766                                   bool is_layered)
767{
768   uint64_t key = 0;
769   uint32_t bit_offset = 0;
770
771   key |= format;
772   bit_offset += 32;
773
774   key |= ((uint64_t) samples) << bit_offset;
775   bit_offset += 4;
776
777   const bool has_depth = (aspects & VK_IMAGE_ASPECT_DEPTH_BIT) ? 1 : 0;
778   key |= ((uint64_t) has_depth) << bit_offset;
779   bit_offset++;
780
781   const bool has_stencil = (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) ? 1 : 0;
782   key |= ((uint64_t) has_stencil) << bit_offset;
783   bit_offset++;;
784
785   key |= (is_layered ? 1ull : 0ull) << bit_offset;
786   bit_offset += 1;
787
788   assert(bit_offset <= 64);
789   return key;
790}
791
792static VkResult
793get_color_clear_pipeline(struct v3dv_device *device,
794                         struct v3dv_render_pass *pass,
795                         uint32_t subpass_idx,
796                         uint32_t rt_idx,
797                         uint32_t attachment_idx,
798                         VkFormat format,
799                         uint32_t samples,
800                         uint32_t components,
801                         bool is_layered,
802                         struct v3dv_meta_color_clear_pipeline **pipeline)
803{
804   assert(vk_format_is_color(format));
805
806   VkResult result = VK_SUCCESS;
807
808   /* If pass != NULL it means that we are emitting the clear as a draw call
809    * in the current pass bound by the application. In that case, we can't
810    * cache the pipeline, since it will be referencing that pass and the
811    * application could be destroying it at any point. Hopefully, the perf
812    * impact is not too big since we still have the device pipeline cache
813    * around and we won't end up re-compiling the clear shader.
814    *
815    * FIXME: alternatively, we could refcount (or maybe clone) the render pass
816    * provided by the application and include it in the pipeline key setup
817    * to make caching safe in this scenario, however, based on tests with
818    * vkQuake3, the fact that we are not caching here doesn't seem to have
819    * any significant impact in performance, so it might not be worth it.
820    */
821   const bool can_cache_pipeline = (pass == NULL);
822
823   uint64_t key;
824   if (can_cache_pipeline) {
825      key = get_color_clear_pipeline_cache_key(rt_idx, format, samples,
826                                               components, is_layered);
827      mtx_lock(&device->meta.mtx);
828      struct hash_entry *entry =
829         _mesa_hash_table_search(device->meta.color_clear.cache, &key);
830      if (entry) {
831         mtx_unlock(&device->meta.mtx);
832         *pipeline = entry->data;
833         return VK_SUCCESS;
834      }
835   }
836
837   *pipeline = vk_zalloc2(&device->vk.alloc, NULL, sizeof(**pipeline), 8,
838                          VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
839
840   if (*pipeline == NULL) {
841      result = VK_ERROR_OUT_OF_HOST_MEMORY;
842      goto fail;
843   }
844
845   if (!pass) {
846      result = create_color_clear_render_pass(device,
847                                              rt_idx,
848                                              format,
849                                              samples,
850                                              &(*pipeline)->pass);
851      if (result != VK_SUCCESS)
852         goto fail;
853
854      pass = v3dv_render_pass_from_handle((*pipeline)->pass);
855   } else {
856      (*pipeline)->pass = v3dv_render_pass_to_handle(pass);
857   }
858
859   result = create_color_clear_pipeline(device,
860                                        pass,
861                                        subpass_idx,
862                                        rt_idx,
863                                        format,
864                                        samples,
865                                        components,
866                                        is_layered,
867                                        device->meta.color_clear.p_layout,
868                                        &(*pipeline)->pipeline);
869   if (result != VK_SUCCESS)
870      goto fail;
871
872   if (can_cache_pipeline) {
873      (*pipeline)->key = key;
874      (*pipeline)->cached = true;
875      _mesa_hash_table_insert(device->meta.color_clear.cache,
876                              &(*pipeline)->key, *pipeline);
877
878      mtx_unlock(&device->meta.mtx);
879   }
880
881   return VK_SUCCESS;
882
883fail:
884   if (can_cache_pipeline)
885      mtx_unlock(&device->meta.mtx);
886
887   VkDevice _device = v3dv_device_to_handle(device);
888   if (*pipeline) {
889      if ((*pipeline)->cached)
890         v3dv_DestroyRenderPass(_device, (*pipeline)->pass, &device->vk.alloc);
891      if ((*pipeline)->pipeline)
892         v3dv_DestroyPipeline(_device, (*pipeline)->pipeline, &device->vk.alloc);
893      vk_free(&device->vk.alloc, *pipeline);
894      *pipeline = NULL;
895   }
896
897   return result;
898}
899
900static VkResult
901get_depth_clear_pipeline(struct v3dv_device *device,
902                         VkImageAspectFlags aspects,
903                         struct v3dv_render_pass *pass,
904                         uint32_t subpass_idx,
905                         uint32_t attachment_idx,
906                         bool is_layered,
907                         struct v3dv_meta_depth_clear_pipeline **pipeline)
908{
909   assert(subpass_idx < pass->subpass_count);
910   assert(attachment_idx != VK_ATTACHMENT_UNUSED);
911   assert(attachment_idx < pass->attachment_count);
912
913   VkResult result = VK_SUCCESS;
914
915   const uint32_t samples = pass->attachments[attachment_idx].desc.samples;
916   const VkFormat format = pass->attachments[attachment_idx].desc.format;
917   assert(vk_format_is_depth_or_stencil(format));
918
919   const uint64_t key =
920      get_depth_clear_pipeline_cache_key(aspects, format, samples, is_layered);
921   mtx_lock(&device->meta.mtx);
922   struct hash_entry *entry =
923      _mesa_hash_table_search(device->meta.depth_clear.cache, &key);
924   if (entry) {
925      mtx_unlock(&device->meta.mtx);
926      *pipeline = entry->data;
927      return VK_SUCCESS;
928   }
929
930   *pipeline = vk_zalloc2(&device->vk.alloc, NULL, sizeof(**pipeline), 8,
931                          VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
932
933   if (*pipeline == NULL) {
934      result = VK_ERROR_OUT_OF_HOST_MEMORY;
935      goto fail;
936   }
937
938   result = create_depth_clear_pipeline(device,
939                                        aspects,
940                                        pass,
941                                        subpass_idx,
942                                        samples,
943                                        is_layered,
944                                        device->meta.depth_clear.p_layout,
945                                        &(*pipeline)->pipeline);
946   if (result != VK_SUCCESS)
947      goto fail;
948
949   (*pipeline)->key = key;
950   _mesa_hash_table_insert(device->meta.depth_clear.cache,
951                           &(*pipeline)->key, *pipeline);
952
953   mtx_unlock(&device->meta.mtx);
954   return VK_SUCCESS;
955
956fail:
957   mtx_unlock(&device->meta.mtx);
958
959   VkDevice _device = v3dv_device_to_handle(device);
960   if (*pipeline) {
961      if ((*pipeline)->pipeline)
962         v3dv_DestroyPipeline(_device, (*pipeline)->pipeline, &device->vk.alloc);
963      vk_free(&device->vk.alloc, *pipeline);
964      *pipeline = NULL;
965   }
966
967   return result;
968}
969
970/* Emits a scissored quad in the clear color */
971static void
972emit_subpass_color_clear_rects(struct v3dv_cmd_buffer *cmd_buffer,
973                               struct v3dv_render_pass *pass,
974                               struct v3dv_subpass *subpass,
975                               uint32_t rt_idx,
976                               const VkClearColorValue *clear_color,
977                               bool is_layered,
978                               bool all_rects_same_layers,
979                               uint32_t rect_count,
980                               const VkClearRect *rects)
981{
982   /* Skip if attachment is unused in the current subpass */
983   assert(rt_idx < subpass->color_count);
984   const uint32_t attachment_idx = subpass->color_attachments[rt_idx].attachment;
985   if (attachment_idx == VK_ATTACHMENT_UNUSED)
986      return;
987
988   /* Obtain a pipeline for this clear */
989   assert(attachment_idx < cmd_buffer->state.pass->attachment_count);
990   const VkFormat format =
991      cmd_buffer->state.pass->attachments[attachment_idx].desc.format;
992   const VkFormat samples =
993      cmd_buffer->state.pass->attachments[attachment_idx].desc.samples;
994   const uint32_t components = VK_COLOR_COMPONENT_R_BIT |
995                               VK_COLOR_COMPONENT_G_BIT |
996                               VK_COLOR_COMPONENT_B_BIT |
997                               VK_COLOR_COMPONENT_A_BIT;
998   struct v3dv_meta_color_clear_pipeline *pipeline = NULL;
999   VkResult result = get_color_clear_pipeline(cmd_buffer->device,
1000                                              pass,
1001                                              cmd_buffer->state.subpass_idx,
1002                                              rt_idx,
1003                                              attachment_idx,
1004                                              format,
1005                                              samples,
1006                                              components,
1007                                              is_layered,
1008                                              &pipeline);
1009   if (result != VK_SUCCESS) {
1010      if (result == VK_ERROR_OUT_OF_HOST_MEMORY)
1011         v3dv_flag_oom(cmd_buffer, NULL);
1012      return;
1013   }
1014   assert(pipeline && pipeline->pipeline);
1015
1016   /* Emit clear rects */
1017   v3dv_cmd_buffer_meta_state_push(cmd_buffer, false);
1018
1019   VkCommandBuffer cmd_buffer_handle = v3dv_cmd_buffer_to_handle(cmd_buffer);
1020   v3dv_CmdPushConstants(cmd_buffer_handle,
1021                         cmd_buffer->device->meta.depth_clear.p_layout,
1022                         VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16,
1023                         clear_color->float32);
1024
1025   v3dv_CmdBindPipeline(cmd_buffer_handle,
1026                        VK_PIPELINE_BIND_POINT_GRAPHICS,
1027                        pipeline->pipeline);
1028
1029   uint32_t dynamic_states = V3DV_CMD_DIRTY_VIEWPORT | V3DV_CMD_DIRTY_SCISSOR;
1030
1031   for (uint32_t i = 0; i < rect_count; i++) {
1032      const VkViewport viewport = {
1033         .x = rects[i].rect.offset.x,
1034         .y = rects[i].rect.offset.y,
1035         .width = rects[i].rect.extent.width,
1036         .height = rects[i].rect.extent.height,
1037         .minDepth = 0.0f,
1038         .maxDepth = 1.0f
1039      };
1040      v3dv_CmdSetViewport(cmd_buffer_handle, 0, 1, &viewport);
1041      v3dv_CmdSetScissor(cmd_buffer_handle, 0, 1, &rects[i].rect);
1042
1043      if (is_layered) {
1044         for (uint32_t layer_offset = 0; layer_offset < rects[i].layerCount;
1045              layer_offset++) {
1046            uint32_t layer = rects[i].baseArrayLayer + layer_offset;
1047            v3dv_CmdPushConstants(cmd_buffer_handle,
1048                                  cmd_buffer->device->meta.depth_clear.p_layout,
1049                                  VK_SHADER_STAGE_GEOMETRY_BIT, 16, 4, &layer);
1050            v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
1051         }
1052      } else {
1053         assert(rects[i].baseArrayLayer == 0 && rects[i].layerCount == 1);
1054         v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
1055      }
1056   }
1057
1058   /* Subpass pipelines can't be cached because they include a reference to the
1059    * render pass currently bound by the application, which means that we need
1060    * to destroy them manually here.
1061    */
1062   assert(!pipeline->cached);
1063   v3dv_cmd_buffer_add_private_obj(
1064      cmd_buffer, (uintptr_t)pipeline,
1065      (v3dv_cmd_buffer_private_obj_destroy_cb) destroy_color_clear_pipeline);
1066
1067   v3dv_cmd_buffer_meta_state_pop(cmd_buffer, dynamic_states, false);
1068}
1069
1070/* Emits a scissored quad, clearing the depth aspect by writing to gl_FragDepth
1071 * and the stencil aspect by using stencil testing.
1072 */
1073static void
1074emit_subpass_ds_clear_rects(struct v3dv_cmd_buffer *cmd_buffer,
1075                            struct v3dv_render_pass *pass,
1076                            struct v3dv_subpass *subpass,
1077                            VkImageAspectFlags aspects,
1078                            const VkClearDepthStencilValue *clear_ds,
1079                            bool is_layered,
1080                            bool all_rects_same_layers,
1081                            uint32_t rect_count,
1082                            const VkClearRect *rects)
1083{
1084   /* Skip if attachment is unused in the current subpass */
1085   const uint32_t attachment_idx = subpass->ds_attachment.attachment;
1086   if (attachment_idx == VK_ATTACHMENT_UNUSED)
1087      return;
1088
1089   /* Obtain a pipeline for this clear */
1090   assert(attachment_idx < cmd_buffer->state.pass->attachment_count);
1091   struct v3dv_meta_depth_clear_pipeline *pipeline = NULL;
1092   VkResult result = get_depth_clear_pipeline(cmd_buffer->device,
1093                                              aspects,
1094                                              pass,
1095                                              cmd_buffer->state.subpass_idx,
1096                                              attachment_idx,
1097                                              is_layered,
1098                                              &pipeline);
1099   if (result != VK_SUCCESS) {
1100      if (result == VK_ERROR_OUT_OF_HOST_MEMORY)
1101         v3dv_flag_oom(cmd_buffer, NULL);
1102      return;
1103   }
1104   assert(pipeline && pipeline->pipeline);
1105
1106   /* Emit clear rects */
1107   v3dv_cmd_buffer_meta_state_push(cmd_buffer, false);
1108
1109   VkCommandBuffer cmd_buffer_handle = v3dv_cmd_buffer_to_handle(cmd_buffer);
1110   v3dv_CmdPushConstants(cmd_buffer_handle,
1111                         cmd_buffer->device->meta.depth_clear.p_layout,
1112                         VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4,
1113                         &clear_ds->depth);
1114
1115   v3dv_CmdBindPipeline(cmd_buffer_handle,
1116                        VK_PIPELINE_BIND_POINT_GRAPHICS,
1117                        pipeline->pipeline);
1118
1119   uint32_t dynamic_states = V3DV_CMD_DIRTY_VIEWPORT | V3DV_CMD_DIRTY_SCISSOR;
1120   if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
1121      v3dv_CmdSetStencilReference(cmd_buffer_handle,
1122                                  VK_STENCIL_FACE_FRONT_AND_BACK,
1123                                  clear_ds->stencil);
1124      v3dv_CmdSetStencilWriteMask(cmd_buffer_handle,
1125                                  VK_STENCIL_FACE_FRONT_AND_BACK, 0xff);
1126      v3dv_CmdSetStencilCompareMask(cmd_buffer_handle,
1127                                    VK_STENCIL_FACE_FRONT_AND_BACK, 0xff);
1128      dynamic_states |= VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK |
1129                        VK_DYNAMIC_STATE_STENCIL_WRITE_MASK |
1130                        VK_DYNAMIC_STATE_STENCIL_REFERENCE;
1131   }
1132
1133   for (uint32_t i = 0; i < rect_count; i++) {
1134      const VkViewport viewport = {
1135         .x = rects[i].rect.offset.x,
1136         .y = rects[i].rect.offset.y,
1137         .width = rects[i].rect.extent.width,
1138         .height = rects[i].rect.extent.height,
1139         .minDepth = 0.0f,
1140         .maxDepth = 1.0f
1141      };
1142      v3dv_CmdSetViewport(cmd_buffer_handle, 0, 1, &viewport);
1143      v3dv_CmdSetScissor(cmd_buffer_handle, 0, 1, &rects[i].rect);
1144      if (is_layered) {
1145         for (uint32_t layer_offset = 0; layer_offset < rects[i].layerCount;
1146              layer_offset++) {
1147            uint32_t layer = rects[i].baseArrayLayer + layer_offset;
1148            v3dv_CmdPushConstants(cmd_buffer_handle,
1149                                  cmd_buffer->device->meta.depth_clear.p_layout,
1150                                  VK_SHADER_STAGE_GEOMETRY_BIT, 4, 4, &layer);
1151            v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
1152         }
1153      } else {
1154         assert(rects[i].baseArrayLayer == 0 && rects[i].layerCount == 1);
1155         v3dv_CmdDraw(cmd_buffer_handle, 4, 1, 0, 0);
1156      }
1157   }
1158
1159   v3dv_cmd_buffer_meta_state_pop(cmd_buffer, dynamic_states, false);
1160}
1161
1162static void
1163gather_layering_info(uint32_t rect_count, const VkClearRect *rects,
1164                     bool *is_layered, bool *all_rects_same_layers)
1165{
1166   *all_rects_same_layers = true;
1167
1168   uint32_t min_layer = rects[0].baseArrayLayer;
1169   uint32_t max_layer = rects[0].baseArrayLayer + rects[0].layerCount - 1;
1170   for (uint32_t i = 1; i < rect_count; i++) {
1171      if (rects[i].baseArrayLayer != rects[i - 1].baseArrayLayer ||
1172          rects[i].layerCount != rects[i - 1].layerCount) {
1173         *all_rects_same_layers = false;
1174         min_layer = MIN2(min_layer, rects[i].baseArrayLayer);
1175         max_layer = MAX2(max_layer, rects[i].baseArrayLayer +
1176                                     rects[i].layerCount - 1);
1177      }
1178   }
1179
1180   *is_layered = !(min_layer == 0 && max_layer == 0);
1181}
1182
1183VKAPI_ATTR void VKAPI_CALL
1184v3dv_CmdClearAttachments(VkCommandBuffer commandBuffer,
1185                         uint32_t attachmentCount,
1186                         const VkClearAttachment *pAttachments,
1187                         uint32_t rectCount,
1188                         const VkClearRect *pRects)
1189{
1190   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
1191
1192   /* We can only clear attachments in the current subpass */
1193   assert(attachmentCount <= 5); /* 4 color + D/S */
1194
1195   struct v3dv_render_pass *pass = cmd_buffer->state.pass;
1196
1197   assert(cmd_buffer->state.subpass_idx < pass->subpass_count);
1198   struct v3dv_subpass *subpass =
1199      &cmd_buffer->state.pass->subpasses[cmd_buffer->state.subpass_idx];
1200
1201   /* Emit a clear rect inside the current job for this subpass. For layered
1202    * framebuffers, we use a geometry shader to redirect clears to the
1203    * appropriate layers.
1204    */
1205   bool is_layered, all_rects_same_layers;
1206   gather_layering_info(rectCount, pRects, &is_layered, &all_rects_same_layers);
1207   for (uint32_t i = 0; i < attachmentCount; i++) {
1208      if (pAttachments[i].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
1209         emit_subpass_color_clear_rects(cmd_buffer, pass, subpass,
1210                                        pAttachments[i].colorAttachment,
1211                                        &pAttachments[i].clearValue.color,
1212                                        is_layered, all_rects_same_layers,
1213                                        rectCount, pRects);
1214      } else {
1215         emit_subpass_ds_clear_rects(cmd_buffer, pass, subpass,
1216                                     pAttachments[i].aspectMask,
1217                                     &pAttachments[i].clearValue.depthStencil,
1218                                     is_layered, all_rects_same_layers,
1219                                     rectCount, pRects);
1220      }
1221   }
1222}
1223