1/* Copyright © 2023 Intel Corporation 2 * SPDX-License-Identifier: MIT 3 */ 4 5#include "libintel_shaders.h" 6 7/* As defined in src/gallium/include/pipe/p_state.h : */ 8struct indirect_indexed_draw { 9 uint32_t count; 10 uint32_t instance_count; 11 uint32_t start; 12 int32_t index_bias; 13 uint32_t start_instance; 14}; 15 16struct indirect_draw { 17 uint32_t count; 18 uint32_t instance_count; 19 uint32_t start; 20 uint32_t start_instance; 21}; 22 23static global void *write_vertex_inputs_iris(global uint32_t *dst_ptr, 24 global void *indirect_ptr, 25 global uint32_t *draw_id_ptr, 26 uint32_t draw_id, 27 bool is_indexed, 28 bool uses_base, 29 bool uses_drawid, 30 uint32_t sgvs_id, 31 uint32_t mocs) 32{ 33 if (!uses_base && !uses_drawid) 34 return dst_ptr; 35 36 uint32_t vertex_buffer_count = 37 (uses_base ? 1 : 0) + (uses_drawid ? 1 : 0); 38 genX(write_3DSTATE_VERTEX_BUFFERS)(dst_ptr, vertex_buffer_count); 39 dst_ptr += 1; /* GENX(3DSTATE_VERTEX_BUFFERS_length); */ 40 if (uses_base) { 41 genX(write_VERTEX_BUFFER_STATE)(dst_ptr, mocs, sgvs_id++, 42 (uint64_t)indirect_ptr, 8, 0); 43 dst_ptr += GENX(VERTEX_BUFFER_STATE_length); 44 } 45 if (uses_drawid) { 46 draw_id_ptr[0] = draw_id; 47 draw_id_ptr[1] = is_indexed ? -1 : 0; 48 genX(write_VERTEX_BUFFER_STATE)(dst_ptr, mocs, sgvs_id++, 49 (uint64_t)draw_id_ptr, 8, 0); 50 dst_ptr += GENX(VERTEX_BUFFER_STATE_length); 51 } 52 return dst_ptr; 53} 54 55static void write_draw_iris(global uint32_t *dst_ptr, 56 global void *indirect_ptr, 57 global uint32_t *draw_id_ptr, 58 uint32_t draw_id, 59 bool is_indexed, 60 bool is_predicated, 61 bool uses_tbimr, 62 bool uses_base, 63 bool uses_drawid, 64 uint32_t sgvs_id, 65 uint32_t mocs) 66{ 67 if (is_indexed) { 68 dst_ptr = write_vertex_inputs_iris(dst_ptr, indirect_ptr + 12, 69 draw_id_ptr, 70 draw_id, is_indexed, 71 uses_base, uses_drawid, 72 sgvs_id, mocs); 73 74 75 struct indirect_indexed_draw data = 76 *((global struct indirect_indexed_draw *)indirect_ptr); 77 78 genX(write_3DPRIMITIVE)(dst_ptr, 79 is_predicated, 80 is_indexed, 81 uses_tbimr, 82 data.count, 83 data.start, 84 data.instance_count, 85 data.start_instance, 86 data.index_bias); 87 } else { 88 dst_ptr = write_vertex_inputs_iris(dst_ptr, indirect_ptr + 8, 89 draw_id_ptr, 90 draw_id, is_indexed, 91 uses_base, uses_drawid, 92 sgvs_id, mocs); 93 94 struct indirect_draw data = 95 *((global struct indirect_draw *)indirect_ptr); 96 97 genX(write_3DPRIMITIVE)(dst_ptr, 98 is_predicated, 99 is_indexed, 100 uses_tbimr, 101 data.count, 102 data.start, 103 data.instance_count, 104 data.start_instance, 105 0 /* base_vertex_location */); 106 } 107} 108 109static void end_generated_draws_iris(global void *dst_ptr, 110 uint32_t item_idx, 111 uint32_t draw_id, uint32_t draw_count, 112 uint32_t ring_count, 113 uint32_t flags, 114 uint64_t gen_addr, uint64_t end_addr) 115{ 116 uint32_t _3dprim_size = ((flags >> 16) & 0xff) * 4; 117 /* We can have an indirect draw count = 0. */ 118 uint32_t last_draw_id = draw_count == 0 ? 0 : (draw_count - 1); 119 global void *jump_dst = draw_count == 0 ? dst_ptr : (dst_ptr + _3dprim_size); 120 121 if (draw_id == last_draw_id) { 122 /* Exit the ring buffer to the next user commands */ 123 genX(write_MI_BATCH_BUFFER_START)(jump_dst, end_addr); 124 } else if (item_idx == (ring_count - 1)) { 125 /* Jump back to the generation shader to generate mode draws */ 126 genX(write_MI_BATCH_BUFFER_START)(jump_dst, gen_addr); 127 } 128} 129 130void 131genX(libiris_write_draw)(global void *dst_base, 132 global void *indirect_base, 133 global void *draw_id_base, 134 uint32_t indirect_stride, 135 global uint32_t *indirect_draw_count, 136 uint32_t draw_base, 137 uint32_t max_draw_count, 138 uint32_t flags, 139 uint32_t ring_count, 140 uint64_t gen_addr, 141 uint64_t end_addr, 142 uint32_t item_idx) 143{ 144 uint32_t _3dprim_size = ((flags >> 16) & 0xff) * 4; 145 uint32_t sgvs_id = flags >> 24; 146 uint32_t draw_id = draw_base + item_idx; 147 uint32_t draw_count = max_draw_count; 148 global void *dst_ptr = dst_base + 149#if GFX_VER >= 12 150 GENX(MI_ARB_CHECK_length) * 4 + 151#endif 152 item_idx * _3dprim_size; 153 global void *indirect_ptr = indirect_base + draw_id * indirect_stride; 154 global void *draw_id_ptr = draw_id_base + item_idx * 8; 155 156 /* Only read the indirect count if we have a valid pointer */ 157 if (indirect_draw_count != 0) 158 draw_count = min(draw_count, *indirect_draw_count); 159 160#if GFX_VER >= 12 161 /* Reenable CS prefetching */ 162 if (item_idx == 0) { 163 struct GENX(MI_ARB_CHECK) v = { 164 GENX(MI_ARB_CHECK_header), 165 /* This is a trick to get the CLC->SPIRV not to use a constant 166 * variable for this. Otherwise we run into issues trying to store 167 * that variable in constant memory which is inefficient for a single 168 * dword and also not handled in our backend. 169 */ 170 .PreParserDisableMask = item_idx == 0, 171 .PreParserDisable = false, 172 }; 173 GENX(MI_ARB_CHECK_pack)(dst_base, &v); 174 } 175#endif 176 177 if (draw_id < draw_count) { 178 bool is_indexed = (flags & ANV_GENERATED_FLAG_INDEXED) != 0; 179 bool is_predicated = (flags & ANV_GENERATED_FLAG_PREDICATED) != 0; 180 bool uses_tbimr = (flags & ANV_GENERATED_FLAG_TBIMR) != 0; 181 bool uses_base = (flags & ANV_GENERATED_FLAG_BASE) != 0; 182 bool uses_drawid = (flags & ANV_GENERATED_FLAG_DRAWID) != 0; 183 uint32_t mocs = (flags >> 8) & 0xff; 184 185 write_draw_iris(dst_ptr, indirect_ptr, draw_id_ptr, 186 draw_id, is_indexed, is_predicated, 187 uses_tbimr, uses_base, uses_drawid, 188 sgvs_id, mocs); 189 } 190 191 end_generated_draws_iris(dst_ptr, item_idx, draw_id, draw_count, 192 ring_count, flags, gen_addr, end_addr); 193} 194