1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © Microsoft Corporation 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 "d3d12_compiler.h" 25bf215546Sopenharmony_ci#include "d3d12_context.h" 26bf215546Sopenharmony_ci#include "d3d12_debug.h" 27bf215546Sopenharmony_ci#include "d3d12_screen.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "nir.h" 30bf215546Sopenharmony_ci#include "compiler/nir/nir_builder.h" 31bf215546Sopenharmony_ci#include "compiler/nir/nir_builtin_builder.h" 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include "util/u_memory.h" 34bf215546Sopenharmony_ci#include "util/u_simple_shaders.h" 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_cistatic nir_ssa_def * 37bf215546Sopenharmony_cinir_cull_face(nir_builder *b, nir_variable *vertices, bool ccw) 38bf215546Sopenharmony_ci{ 39bf215546Sopenharmony_ci nir_ssa_def *v0 = 40bf215546Sopenharmony_ci nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 0))); 41bf215546Sopenharmony_ci nir_ssa_def *v1 = 42bf215546Sopenharmony_ci nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 1))); 43bf215546Sopenharmony_ci nir_ssa_def *v2 = 44bf215546Sopenharmony_ci nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 2))); 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci nir_ssa_def *dir = nir_fdot(b, nir_cross4(b, nir_fsub(b, v1, v0), 47bf215546Sopenharmony_ci nir_fsub(b, v2, v0)), 48bf215546Sopenharmony_ci nir_imm_vec4(b, 0.0, 0.0, -1.0, 0.0)); 49bf215546Sopenharmony_ci if (ccw) 50bf215546Sopenharmony_ci return nir_fge(b, nir_imm_int(b, 0), dir); 51bf215546Sopenharmony_ci else 52bf215546Sopenharmony_ci return nir_flt(b, nir_imm_int(b, 0), dir); 53bf215546Sopenharmony_ci} 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_cistatic void 56bf215546Sopenharmony_cicopy_vars(nir_builder *b, nir_deref_instr *dst, nir_deref_instr *src) 57bf215546Sopenharmony_ci{ 58bf215546Sopenharmony_ci assert(glsl_get_bare_type(dst->type) == glsl_get_bare_type(src->type)); 59bf215546Sopenharmony_ci if (glsl_type_is_struct(dst->type)) { 60bf215546Sopenharmony_ci for (unsigned i = 0; i < glsl_get_length(dst->type); ++i) { 61bf215546Sopenharmony_ci copy_vars(b, nir_build_deref_struct(b, dst, i), nir_build_deref_struct(b, src, i)); 62bf215546Sopenharmony_ci } 63bf215546Sopenharmony_ci } else if (glsl_type_is_array_or_matrix(dst->type)) { 64bf215546Sopenharmony_ci copy_vars(b, nir_build_deref_array_wildcard(b, dst), nir_build_deref_array_wildcard(b, src)); 65bf215546Sopenharmony_ci } else { 66bf215546Sopenharmony_ci nir_copy_deref(b, dst, src); 67bf215546Sopenharmony_ci } 68bf215546Sopenharmony_ci} 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_cistatic d3d12_shader_selector* 71bf215546Sopenharmony_cid3d12_make_passthrough_gs(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key) 72bf215546Sopenharmony_ci{ 73bf215546Sopenharmony_ci struct d3d12_shader_selector *gs; 74bf215546Sopenharmony_ci uint64_t varyings = key->varyings.mask; 75bf215546Sopenharmony_ci nir_shader *nir; 76bf215546Sopenharmony_ci struct pipe_shader_state templ; 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, 79bf215546Sopenharmony_ci &d3d12_screen(ctx->base.screen)->nir_options, 80bf215546Sopenharmony_ci "passthrough"); 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci nir = b.shader; 83bf215546Sopenharmony_ci nir->info.inputs_read = varyings; 84bf215546Sopenharmony_ci nir->info.outputs_written = varyings; 85bf215546Sopenharmony_ci nir->info.gs.input_primitive = GL_POINTS; 86bf215546Sopenharmony_ci nir->info.gs.output_primitive = GL_POINTS; 87bf215546Sopenharmony_ci nir->info.gs.vertices_in = 1; 88bf215546Sopenharmony_ci nir->info.gs.vertices_out = 1; 89bf215546Sopenharmony_ci nir->info.gs.invocations = 1; 90bf215546Sopenharmony_ci nir->info.gs.active_stream_mask = 1; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci /* Copy inputs to outputs. */ 93bf215546Sopenharmony_ci while (varyings) { 94bf215546Sopenharmony_ci char tmp[100]; 95bf215546Sopenharmony_ci const int i = u_bit_scan64(&varyings); 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci unsigned frac_slots = key->varyings.slots[i].location_frac_mask; 98bf215546Sopenharmony_ci while (frac_slots) { 99bf215546Sopenharmony_ci nir_variable *in, *out; 100bf215546Sopenharmony_ci int j = u_bit_scan(&frac_slots); 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci snprintf(tmp, ARRAY_SIZE(tmp), "in_%d", key->varyings.slots[i].vars[j].driver_location); 103bf215546Sopenharmony_ci in = nir_variable_create(nir, 104bf215546Sopenharmony_ci nir_var_shader_in, 105bf215546Sopenharmony_ci glsl_array_type(key->varyings.slots[i].types[j], 1, false), 106bf215546Sopenharmony_ci tmp); 107bf215546Sopenharmony_ci in->data.location = i; 108bf215546Sopenharmony_ci in->data.location_frac = j; 109bf215546Sopenharmony_ci in->data.driver_location = key->varyings.slots[i].vars[j].driver_location; 110bf215546Sopenharmony_ci in->data.interpolation = key->varyings.slots[i].vars[j].interpolation; 111bf215546Sopenharmony_ci in->data.compact = key->varyings.slots[i].vars[j].compact; 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci snprintf(tmp, ARRAY_SIZE(tmp), "out_%d", key->varyings.slots[i].vars[j].driver_location); 114bf215546Sopenharmony_ci out = nir_variable_create(nir, 115bf215546Sopenharmony_ci nir_var_shader_out, 116bf215546Sopenharmony_ci key->varyings.slots[i].types[j], 117bf215546Sopenharmony_ci tmp); 118bf215546Sopenharmony_ci out->data.location = i; 119bf215546Sopenharmony_ci out->data.location_frac = j; 120bf215546Sopenharmony_ci out->data.driver_location = key->varyings.slots[i].vars[j].driver_location; 121bf215546Sopenharmony_ci out->data.interpolation = key->varyings.slots[i].vars[j].interpolation; 122bf215546Sopenharmony_ci out->data.compact = key->varyings.slots[i].vars[j].compact; 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci nir_deref_instr *in_value = nir_build_deref_array(&b, nir_build_deref_var(&b, in), 125bf215546Sopenharmony_ci nir_imm_int(&b, 0)); 126bf215546Sopenharmony_ci copy_vars(&b, nir_build_deref_var(&b, out), in_value); 127bf215546Sopenharmony_ci } 128bf215546Sopenharmony_ci } 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci nir_emit_vertex(&b, 0); 131bf215546Sopenharmony_ci nir_end_primitive(&b, 0); 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_lower_var_copies); 134bf215546Sopenharmony_ci nir_validate_shader(nir, "in d3d12_create_passthrough_gs"); 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci templ.type = PIPE_SHADER_IR_NIR; 137bf215546Sopenharmony_ci templ.ir.nir = nir; 138bf215546Sopenharmony_ci templ.stream_output.num_outputs = 0; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci gs = d3d12_create_shader(ctx, PIPE_SHADER_GEOMETRY, &templ); 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci return gs; 143bf215546Sopenharmony_ci} 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_cistruct emit_primitives_context 146bf215546Sopenharmony_ci{ 147bf215546Sopenharmony_ci struct d3d12_context *ctx; 148bf215546Sopenharmony_ci nir_builder b; 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci unsigned num_vars; 151bf215546Sopenharmony_ci nir_variable *in[VARYING_SLOT_MAX]; 152bf215546Sopenharmony_ci nir_variable *out[VARYING_SLOT_MAX]; 153bf215546Sopenharmony_ci nir_variable *front_facing_var; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci nir_loop *loop; 156bf215546Sopenharmony_ci nir_deref_instr *loop_index_deref; 157bf215546Sopenharmony_ci nir_ssa_def *loop_index; 158bf215546Sopenharmony_ci nir_ssa_def *edgeflag_cmp; 159bf215546Sopenharmony_ci nir_ssa_def *front_facing; 160bf215546Sopenharmony_ci}; 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_cistatic bool 163bf215546Sopenharmony_cid3d12_begin_emit_primitives_gs(struct emit_primitives_context *emit_ctx, 164bf215546Sopenharmony_ci struct d3d12_context *ctx, 165bf215546Sopenharmony_ci struct d3d12_gs_variant_key *key, 166bf215546Sopenharmony_ci uint16_t output_primitive, 167bf215546Sopenharmony_ci unsigned vertices_out) 168bf215546Sopenharmony_ci{ 169bf215546Sopenharmony_ci nir_builder *b = &emit_ctx->b; 170bf215546Sopenharmony_ci nir_variable *edgeflag_var = NULL; 171bf215546Sopenharmony_ci nir_variable *pos_var = NULL; 172bf215546Sopenharmony_ci uint64_t varyings = key->varyings.mask; 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci emit_ctx->ctx = ctx; 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci emit_ctx->b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, 177bf215546Sopenharmony_ci &d3d12_screen(ctx->base.screen)->nir_options, 178bf215546Sopenharmony_ci "edgeflags"); 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci nir_shader *nir = b->shader; 181bf215546Sopenharmony_ci nir->info.inputs_read = varyings; 182bf215546Sopenharmony_ci nir->info.outputs_written = varyings; 183bf215546Sopenharmony_ci nir->info.gs.input_primitive = GL_TRIANGLES; 184bf215546Sopenharmony_ci nir->info.gs.output_primitive = output_primitive; 185bf215546Sopenharmony_ci nir->info.gs.vertices_in = 3; 186bf215546Sopenharmony_ci nir->info.gs.vertices_out = vertices_out; 187bf215546Sopenharmony_ci nir->info.gs.invocations = 1; 188bf215546Sopenharmony_ci nir->info.gs.active_stream_mask = 1; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci while (varyings) { 191bf215546Sopenharmony_ci char tmp[100]; 192bf215546Sopenharmony_ci const int i = u_bit_scan64(&varyings); 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci unsigned frac_slots = key->varyings.slots[i].location_frac_mask; 195bf215546Sopenharmony_ci while (frac_slots) { 196bf215546Sopenharmony_ci int j = u_bit_scan(&frac_slots); 197bf215546Sopenharmony_ci snprintf(tmp, ARRAY_SIZE(tmp), "in_%d", emit_ctx->num_vars); 198bf215546Sopenharmony_ci emit_ctx->in[emit_ctx->num_vars] = nir_variable_create(nir, 199bf215546Sopenharmony_ci nir_var_shader_in, 200bf215546Sopenharmony_ci glsl_array_type(key->varyings.slots[i].types[j], 3, 0), 201bf215546Sopenharmony_ci tmp); 202bf215546Sopenharmony_ci emit_ctx->in[emit_ctx->num_vars]->data.location = i; 203bf215546Sopenharmony_ci emit_ctx->in[emit_ctx->num_vars]->data.location_frac = j; 204bf215546Sopenharmony_ci emit_ctx->in[emit_ctx->num_vars]->data.driver_location = key->varyings.slots[i].vars[j].driver_location; 205bf215546Sopenharmony_ci emit_ctx->in[emit_ctx->num_vars]->data.interpolation = key->varyings.slots[i].vars[j].interpolation; 206bf215546Sopenharmony_ci emit_ctx->in[emit_ctx->num_vars]->data.compact = key->varyings.slots[i].vars[j].compact; 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci /* Don't create an output for the edge flag variable */ 209bf215546Sopenharmony_ci if (i == VARYING_SLOT_EDGE) { 210bf215546Sopenharmony_ci edgeflag_var = emit_ctx->in[emit_ctx->num_vars]; 211bf215546Sopenharmony_ci continue; 212bf215546Sopenharmony_ci } else if (i == VARYING_SLOT_POS) { 213bf215546Sopenharmony_ci pos_var = emit_ctx->in[emit_ctx->num_vars]; 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci snprintf(tmp, ARRAY_SIZE(tmp), "out_%d", emit_ctx->num_vars); 217bf215546Sopenharmony_ci emit_ctx->out[emit_ctx->num_vars] = nir_variable_create(nir, 218bf215546Sopenharmony_ci nir_var_shader_out, 219bf215546Sopenharmony_ci key->varyings.slots[i].types[j], 220bf215546Sopenharmony_ci tmp); 221bf215546Sopenharmony_ci emit_ctx->out[emit_ctx->num_vars]->data.location = i; 222bf215546Sopenharmony_ci emit_ctx->out[emit_ctx->num_vars]->data.location_frac = j; 223bf215546Sopenharmony_ci emit_ctx->out[emit_ctx->num_vars]->data.driver_location = key->varyings.slots[i].vars[j].driver_location; 224bf215546Sopenharmony_ci emit_ctx->out[emit_ctx->num_vars]->data.interpolation = key->varyings.slots[i].vars[j].interpolation; 225bf215546Sopenharmony_ci emit_ctx->out[emit_ctx->num_vars]->data.compact = key->varyings.slots[i].vars[j].compact; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci emit_ctx->num_vars++; 228bf215546Sopenharmony_ci } 229bf215546Sopenharmony_ci } 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci if (key->has_front_face) { 232bf215546Sopenharmony_ci emit_ctx->front_facing_var = nir_variable_create(nir, 233bf215546Sopenharmony_ci nir_var_shader_out, 234bf215546Sopenharmony_ci glsl_uint_type(), 235bf215546Sopenharmony_ci "gl_FrontFacing"); 236bf215546Sopenharmony_ci emit_ctx->front_facing_var->data.location = VARYING_SLOT_VAR12; 237bf215546Sopenharmony_ci emit_ctx->front_facing_var->data.driver_location = emit_ctx->num_vars; 238bf215546Sopenharmony_ci emit_ctx->front_facing_var->data.interpolation = INTERP_MODE_FLAT; 239bf215546Sopenharmony_ci } 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci /* Temporary variable "loop_index" to loop over input vertices */ 242bf215546Sopenharmony_ci nir_function_impl *impl = nir_shader_get_entrypoint(nir); 243bf215546Sopenharmony_ci nir_variable *loop_index_var = 244bf215546Sopenharmony_ci nir_local_variable_create(impl, glsl_uint_type(), "loop_index"); 245bf215546Sopenharmony_ci emit_ctx->loop_index_deref = nir_build_deref_var(b, loop_index_var); 246bf215546Sopenharmony_ci nir_store_deref(b, emit_ctx->loop_index_deref, nir_imm_int(b, 0), 1); 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci nir_ssa_def *diagonal_vertex = NULL; 249bf215546Sopenharmony_ci if (key->edge_flag_fix) { 250bf215546Sopenharmony_ci nir_ssa_def *prim_id = nir_load_primitive_id(b); 251bf215546Sopenharmony_ci nir_ssa_def *odd = nir_build_alu(b, nir_op_imod, 252bf215546Sopenharmony_ci prim_id, 253bf215546Sopenharmony_ci nir_imm_int(b, 2), 254bf215546Sopenharmony_ci NULL, NULL); 255bf215546Sopenharmony_ci diagonal_vertex = nir_bcsel(b, nir_i2b(b, odd), 256bf215546Sopenharmony_ci nir_imm_int(b, 2), 257bf215546Sopenharmony_ci nir_imm_int(b, 1)); 258bf215546Sopenharmony_ci } 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci if (key->cull_mode != PIPE_FACE_NONE || key->has_front_face) { 261bf215546Sopenharmony_ci if (key->cull_mode == PIPE_FACE_BACK) 262bf215546Sopenharmony_ci emit_ctx->edgeflag_cmp = nir_cull_face(b, pos_var, key->front_ccw); 263bf215546Sopenharmony_ci else if (key->cull_mode == PIPE_FACE_FRONT) 264bf215546Sopenharmony_ci emit_ctx->edgeflag_cmp = nir_cull_face(b, pos_var, !key->front_ccw); 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci if (key->has_front_face) { 267bf215546Sopenharmony_ci if (key->cull_mode == PIPE_FACE_BACK) 268bf215546Sopenharmony_ci emit_ctx->front_facing = emit_ctx->edgeflag_cmp; 269bf215546Sopenharmony_ci else 270bf215546Sopenharmony_ci emit_ctx->front_facing = nir_cull_face(b, pos_var, key->front_ccw); 271bf215546Sopenharmony_ci emit_ctx->front_facing = nir_i2i32(b, emit_ctx->front_facing); 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci } 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci /** 276bf215546Sopenharmony_ci * while { 277bf215546Sopenharmony_ci * if (loop_index >= 3) 278bf215546Sopenharmony_ci * break; 279bf215546Sopenharmony_ci */ 280bf215546Sopenharmony_ci emit_ctx->loop = nir_push_loop(b); 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci emit_ctx->loop_index = nir_load_deref(b, emit_ctx->loop_index_deref); 283bf215546Sopenharmony_ci nir_ssa_def *cmp = nir_ige(b, emit_ctx->loop_index, 284bf215546Sopenharmony_ci nir_imm_int(b, 3)); 285bf215546Sopenharmony_ci nir_if *loop_check = nir_push_if(b, cmp); 286bf215546Sopenharmony_ci nir_jump(b, nir_jump_break); 287bf215546Sopenharmony_ci nir_pop_if(b, loop_check); 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci if (edgeflag_var) { 290bf215546Sopenharmony_ci nir_ssa_def *edge_flag = 291bf215546Sopenharmony_ci nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, edgeflag_var), emit_ctx->loop_index)); 292bf215546Sopenharmony_ci nir_ssa_def *is_edge = nir_feq(b, nir_channel(b, edge_flag, 0), nir_imm_float(b, 1.0)); 293bf215546Sopenharmony_ci if (emit_ctx->edgeflag_cmp) 294bf215546Sopenharmony_ci emit_ctx->edgeflag_cmp = nir_iand(b, emit_ctx->edgeflag_cmp, is_edge); 295bf215546Sopenharmony_ci else 296bf215546Sopenharmony_ci emit_ctx->edgeflag_cmp = is_edge; 297bf215546Sopenharmony_ci } 298bf215546Sopenharmony_ci 299bf215546Sopenharmony_ci if (key->edge_flag_fix) { 300bf215546Sopenharmony_ci nir_ssa_def *is_edge = nir_ine(b, emit_ctx->loop_index, diagonal_vertex); 301bf215546Sopenharmony_ci if (emit_ctx->edgeflag_cmp) 302bf215546Sopenharmony_ci emit_ctx->edgeflag_cmp = nir_iand(b, emit_ctx->edgeflag_cmp, is_edge); 303bf215546Sopenharmony_ci else 304bf215546Sopenharmony_ci emit_ctx->edgeflag_cmp = is_edge; 305bf215546Sopenharmony_ci } 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ci return true; 308bf215546Sopenharmony_ci} 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_cistatic struct d3d12_shader_selector * 311bf215546Sopenharmony_cid3d12_finish_emit_primitives_gs(struct emit_primitives_context *emit_ctx, bool end_primitive) 312bf215546Sopenharmony_ci{ 313bf215546Sopenharmony_ci struct pipe_shader_state templ; 314bf215546Sopenharmony_ci nir_builder *b = &emit_ctx->b; 315bf215546Sopenharmony_ci nir_shader *nir = b->shader; 316bf215546Sopenharmony_ci 317bf215546Sopenharmony_ci /** 318bf215546Sopenharmony_ci * loop_index++; 319bf215546Sopenharmony_ci * } 320bf215546Sopenharmony_ci */ 321bf215546Sopenharmony_ci nir_store_deref(b, emit_ctx->loop_index_deref, nir_iadd_imm(b, emit_ctx->loop_index, 1), 1); 322bf215546Sopenharmony_ci nir_pop_loop(b, emit_ctx->loop); 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci if (end_primitive) 325bf215546Sopenharmony_ci nir_end_primitive(b, 0); 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci nir_validate_shader(nir, "in d3d12_lower_edge_flags"); 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_lower_var_copies); 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci templ.type = PIPE_SHADER_IR_NIR; 332bf215546Sopenharmony_ci templ.ir.nir = nir; 333bf215546Sopenharmony_ci templ.stream_output.num_outputs = 0; 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci return d3d12_create_shader(emit_ctx->ctx, PIPE_SHADER_GEOMETRY, &templ); 336bf215546Sopenharmony_ci} 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_cistatic d3d12_shader_selector* 339bf215546Sopenharmony_cid3d12_emit_points(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key) 340bf215546Sopenharmony_ci{ 341bf215546Sopenharmony_ci struct emit_primitives_context emit_ctx = {0}; 342bf215546Sopenharmony_ci nir_builder *b = &emit_ctx.b; 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci d3d12_begin_emit_primitives_gs(&emit_ctx, ctx, key, GL_POINTS, 3); 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci /** 347bf215546Sopenharmony_ci * if (edge_flag) 348bf215546Sopenharmony_ci * out_position = in_position; 349bf215546Sopenharmony_ci * else 350bf215546Sopenharmony_ci * out_position = vec4(-2.0, -2.0, 0.0, 1.0); // Invalid position 351bf215546Sopenharmony_ci * 352bf215546Sopenharmony_ci * [...] // Copy other variables 353bf215546Sopenharmony_ci * 354bf215546Sopenharmony_ci * EmitVertex(); 355bf215546Sopenharmony_ci */ 356bf215546Sopenharmony_ci for (unsigned i = 0; i < emit_ctx.num_vars; ++i) { 357bf215546Sopenharmony_ci nir_ssa_def *index = (key->flat_varyings & (1ull << emit_ctx.in[i]->data.location)) ? 358bf215546Sopenharmony_ci nir_imm_int(b, (key->flatshade_first ? 0 : 2)) : emit_ctx.loop_index; 359bf215546Sopenharmony_ci nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index); 360bf215546Sopenharmony_ci if (emit_ctx.in[i]->data.location == VARYING_SLOT_POS && emit_ctx.edgeflag_cmp) { 361bf215546Sopenharmony_ci nir_if *edge_check = nir_push_if(b, emit_ctx.edgeflag_cmp); 362bf215546Sopenharmony_ci copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value); 363bf215546Sopenharmony_ci nir_if *edge_else = nir_push_else(b, edge_check); 364bf215546Sopenharmony_ci nir_store_deref(b, nir_build_deref_var(b, emit_ctx.out[i]), 365bf215546Sopenharmony_ci nir_imm_vec4(b, -2.0, -2.0, 0.0, 1.0), 0xf); 366bf215546Sopenharmony_ci nir_pop_if(b, edge_else); 367bf215546Sopenharmony_ci } else { 368bf215546Sopenharmony_ci copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value); 369bf215546Sopenharmony_ci } 370bf215546Sopenharmony_ci } 371bf215546Sopenharmony_ci if (key->has_front_face) 372bf215546Sopenharmony_ci nir_store_var(b, emit_ctx.front_facing_var, emit_ctx.front_facing, 0x1); 373bf215546Sopenharmony_ci nir_emit_vertex(b, 0); 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_ci return d3d12_finish_emit_primitives_gs(&emit_ctx, false); 376bf215546Sopenharmony_ci} 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_cistatic d3d12_shader_selector* 379bf215546Sopenharmony_cid3d12_emit_lines(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key) 380bf215546Sopenharmony_ci{ 381bf215546Sopenharmony_ci struct emit_primitives_context emit_ctx = {0}; 382bf215546Sopenharmony_ci nir_builder *b = &emit_ctx.b; 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci d3d12_begin_emit_primitives_gs(&emit_ctx, ctx, key, GL_LINE_STRIP, 6); 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci nir_ssa_def *next_index = nir_imod(b, nir_iadd_imm(b, emit_ctx.loop_index, 1), nir_imm_int(b, 3)); 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_ci /* First vertex */ 389bf215546Sopenharmony_ci for (unsigned i = 0; i < emit_ctx.num_vars; ++i) { 390bf215546Sopenharmony_ci nir_ssa_def *index = (key->flat_varyings & (1ull << emit_ctx.in[i]->data.location)) ? 391bf215546Sopenharmony_ci nir_imm_int(b, (key->flatshade_first ? 0 : 2)) : emit_ctx.loop_index; 392bf215546Sopenharmony_ci nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index); 393bf215546Sopenharmony_ci copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value); 394bf215546Sopenharmony_ci } 395bf215546Sopenharmony_ci if (key->has_front_face) 396bf215546Sopenharmony_ci nir_store_var(b, emit_ctx.front_facing_var, emit_ctx.front_facing, 0x1); 397bf215546Sopenharmony_ci nir_emit_vertex(b, 0); 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci /* Second vertex. If not an edge, use same position as first vertex */ 400bf215546Sopenharmony_ci for (unsigned i = 0; i < emit_ctx.num_vars; ++i) { 401bf215546Sopenharmony_ci nir_ssa_def *index = next_index; 402bf215546Sopenharmony_ci if (emit_ctx.in[i]->data.location == VARYING_SLOT_POS) 403bf215546Sopenharmony_ci index = nir_bcsel(b, emit_ctx.edgeflag_cmp, next_index, emit_ctx.loop_index); 404bf215546Sopenharmony_ci else if (key->flat_varyings & (1ull << emit_ctx.in[i]->data.location)) 405bf215546Sopenharmony_ci index = nir_imm_int(b, 2); 406bf215546Sopenharmony_ci copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]), 407bf215546Sopenharmony_ci nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index)); 408bf215546Sopenharmony_ci } 409bf215546Sopenharmony_ci if (key->has_front_face) 410bf215546Sopenharmony_ci nir_store_var(b, emit_ctx.front_facing_var, emit_ctx.front_facing, 0x1); 411bf215546Sopenharmony_ci nir_emit_vertex(b, 0); 412bf215546Sopenharmony_ci 413bf215546Sopenharmony_ci nir_end_primitive(b, 0); 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci return d3d12_finish_emit_primitives_gs(&emit_ctx, false); 416bf215546Sopenharmony_ci} 417bf215546Sopenharmony_ci 418bf215546Sopenharmony_cistatic d3d12_shader_selector* 419bf215546Sopenharmony_cid3d12_emit_triangles(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key) 420bf215546Sopenharmony_ci{ 421bf215546Sopenharmony_ci struct emit_primitives_context emit_ctx = {0}; 422bf215546Sopenharmony_ci nir_builder *b = &emit_ctx.b; 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci d3d12_begin_emit_primitives_gs(&emit_ctx, ctx, key, GL_TRIANGLE_STRIP, 3); 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci /** 427bf215546Sopenharmony_ci * [...] // Copy variables 428bf215546Sopenharmony_ci * 429bf215546Sopenharmony_ci * EmitVertex(); 430bf215546Sopenharmony_ci */ 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci nir_ssa_def *incr = NULL; 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_ci if (key->provoking_vertex > 0) 435bf215546Sopenharmony_ci incr = nir_imm_int(b, key->provoking_vertex); 436bf215546Sopenharmony_ci else 437bf215546Sopenharmony_ci incr = nir_imm_int(b, 3); 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci if (key->alternate_tri) { 440bf215546Sopenharmony_ci nir_ssa_def *odd = nir_imod(b, nir_load_primitive_id(b), nir_imm_int(b, 2)); 441bf215546Sopenharmony_ci incr = nir_isub(b, incr, odd); 442bf215546Sopenharmony_ci } 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_ci assert(incr != NULL); 445bf215546Sopenharmony_ci nir_ssa_def *index = nir_imod(b, nir_iadd(b, emit_ctx.loop_index, incr), nir_imm_int(b, 3)); 446bf215546Sopenharmony_ci for (unsigned i = 0; i < emit_ctx.num_vars; ++i) { 447bf215546Sopenharmony_ci nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index); 448bf215546Sopenharmony_ci copy_vars(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value); 449bf215546Sopenharmony_ci } 450bf215546Sopenharmony_ci nir_emit_vertex(b, 0); 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci return d3d12_finish_emit_primitives_gs(&emit_ctx, true); 453bf215546Sopenharmony_ci} 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_cistatic uint32_t 456bf215546Sopenharmony_cihash_gs_variant_key(const void *key) 457bf215546Sopenharmony_ci{ 458bf215546Sopenharmony_ci return _mesa_hash_data(key, sizeof(struct d3d12_gs_variant_key)); 459bf215546Sopenharmony_ci} 460bf215546Sopenharmony_ci 461bf215546Sopenharmony_cistatic bool 462bf215546Sopenharmony_ciequals_gs_variant_key(const void *a, const void *b) 463bf215546Sopenharmony_ci{ 464bf215546Sopenharmony_ci return memcmp(a, b, sizeof(struct d3d12_gs_variant_key)) == 0; 465bf215546Sopenharmony_ci} 466bf215546Sopenharmony_ci 467bf215546Sopenharmony_civoid 468bf215546Sopenharmony_cid3d12_gs_variant_cache_init(struct d3d12_context *ctx) 469bf215546Sopenharmony_ci{ 470bf215546Sopenharmony_ci ctx->gs_variant_cache = _mesa_hash_table_create(NULL, NULL, equals_gs_variant_key); 471bf215546Sopenharmony_ci} 472bf215546Sopenharmony_ci 473bf215546Sopenharmony_cistatic void 474bf215546Sopenharmony_cidelete_entry(struct hash_entry *entry) 475bf215546Sopenharmony_ci{ 476bf215546Sopenharmony_ci d3d12_shader_free((d3d12_shader_selector *)entry->data); 477bf215546Sopenharmony_ci} 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_civoid 480bf215546Sopenharmony_cid3d12_gs_variant_cache_destroy(struct d3d12_context *ctx) 481bf215546Sopenharmony_ci{ 482bf215546Sopenharmony_ci _mesa_hash_table_destroy(ctx->gs_variant_cache, delete_entry); 483bf215546Sopenharmony_ci} 484bf215546Sopenharmony_ci 485bf215546Sopenharmony_cistatic struct d3d12_shader_selector * 486bf215546Sopenharmony_cicreate_geometry_shader_variant(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key) 487bf215546Sopenharmony_ci{ 488bf215546Sopenharmony_ci d3d12_shader_selector *gs = NULL; 489bf215546Sopenharmony_ci 490bf215546Sopenharmony_ci if (key->passthrough) 491bf215546Sopenharmony_ci gs = d3d12_make_passthrough_gs(ctx, key); 492bf215546Sopenharmony_ci else if (key->provoking_vertex > 0 || key->alternate_tri) 493bf215546Sopenharmony_ci gs = d3d12_emit_triangles(ctx, key); 494bf215546Sopenharmony_ci else if (key->fill_mode == PIPE_POLYGON_MODE_POINT) 495bf215546Sopenharmony_ci gs = d3d12_emit_points(ctx, key); 496bf215546Sopenharmony_ci else if (key->fill_mode == PIPE_POLYGON_MODE_LINE) 497bf215546Sopenharmony_ci gs = d3d12_emit_lines(ctx, key); 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_ci if (gs) { 500bf215546Sopenharmony_ci gs->is_variant = true; 501bf215546Sopenharmony_ci gs->gs_key = *key; 502bf215546Sopenharmony_ci } 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci return gs; 505bf215546Sopenharmony_ci} 506bf215546Sopenharmony_ci 507bf215546Sopenharmony_cid3d12_shader_selector * 508bf215546Sopenharmony_cid3d12_get_gs_variant(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key) 509bf215546Sopenharmony_ci{ 510bf215546Sopenharmony_ci uint32_t hash = hash_gs_variant_key(key); 511bf215546Sopenharmony_ci struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->gs_variant_cache, 512bf215546Sopenharmony_ci hash, key); 513bf215546Sopenharmony_ci if (!entry) { 514bf215546Sopenharmony_ci d3d12_shader_selector *gs = create_geometry_shader_variant(ctx, key); 515bf215546Sopenharmony_ci entry = _mesa_hash_table_insert_pre_hashed(ctx->gs_variant_cache, 516bf215546Sopenharmony_ci hash, &gs->gs_key, gs); 517bf215546Sopenharmony_ci assert(entry); 518bf215546Sopenharmony_ci } 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_ci return (d3d12_shader_selector *)entry->data; 521bf215546Sopenharmony_ci} 522