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