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