Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_nir_passes.c
4570 views
/*1* Copyright © Microsoft Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* on the rights to use, copy, modify, merge, publish, distribute, sub7* license, and/or sell copies of the Software, and to permit persons to whom8* the Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,18* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR19* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE20* USE OR OTHER DEALINGS IN THE SOFTWARE.21*/2223#include "d3d12_nir_passes.h"24#include "d3d12_compiler.h"25#include "nir_builder.h"26#include "nir_builtin_builder.h"27#include "nir_format_convert.h"28#include "program/prog_instruction.h"29#include "dxil_nir.h"3031/**32* Lower Y Flip:33*34* We can't do a Y flip simply by negating the viewport height,35* so we need to lower the flip into the NIR shader.36*/3738static nir_ssa_def *39get_state_var(nir_builder *b,40enum d3d12_state_var var_enum,41const char *var_name,42const struct glsl_type *var_type,43nir_variable **out_var)44{45const gl_state_index16 tokens[STATE_LENGTH] = { STATE_INTERNAL_DRIVER, var_enum };46if (*out_var == NULL) {47nir_variable *var = nir_variable_create(b->shader,48nir_var_uniform,49var_type,50var_name);5152var->num_state_slots = 1;53var->state_slots = ralloc_array(var, nir_state_slot, 1);54memcpy(var->state_slots[0].tokens, tokens,55sizeof(var->state_slots[0].tokens));56var->data.how_declared = nir_var_hidden;57b->shader->num_uniforms++;58*out_var = var;59}60return nir_load_var(b, *out_var);61}6263static void64lower_pos_write(nir_builder *b, struct nir_instr *instr, nir_variable **flip)65{66if (instr->type != nir_instr_type_intrinsic)67return;6869nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);70if (intr->intrinsic != nir_intrinsic_store_deref)71return;7273nir_variable *var = nir_intrinsic_get_var(intr, 0);74if (var->data.mode != nir_var_shader_out ||75var->data.location != VARYING_SLOT_POS)76return;7778b->cursor = nir_before_instr(&intr->instr);7980nir_ssa_def *pos = nir_ssa_for_src(b, intr->src[1], 4);81nir_ssa_def *flip_y = get_state_var(b, D3D12_STATE_VAR_Y_FLIP, "d3d12_FlipY",82glsl_float_type(), flip);83nir_ssa_def *def = nir_vec4(b,84nir_channel(b, pos, 0),85nir_fmul(b, nir_channel(b, pos, 1), flip_y),86nir_channel(b, pos, 2),87nir_channel(b, pos, 3));88nir_instr_rewrite_src(&intr->instr, intr->src + 1, nir_src_for_ssa(def));89}9091void92d3d12_lower_yflip(nir_shader *nir)93{94nir_variable *flip = NULL;9596if (nir->info.stage != MESA_SHADER_VERTEX &&97nir->info.stage != MESA_SHADER_GEOMETRY)98return;99100nir_foreach_function(function, nir) {101if (function->impl) {102nir_builder b;103nir_builder_init(&b, function->impl);104105nir_foreach_block(block, function->impl) {106nir_foreach_instr_safe(instr, block) {107lower_pos_write(&b, instr, &flip);108}109}110111nir_metadata_preserve(function->impl, nir_metadata_block_index |112nir_metadata_dominance);113}114}115}116117static void118lower_load_face(nir_builder *b, struct nir_instr *instr, nir_variable *var)119{120if (instr->type != nir_instr_type_intrinsic)121return;122123nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);124if (intr->intrinsic != nir_intrinsic_load_front_face)125return;126127b->cursor = nir_before_instr(&intr->instr);128129nir_ssa_def *load = nir_load_var(b, var);130131nir_ssa_def_rewrite_uses(&intr->dest.ssa, load);132nir_instr_remove(instr);133}134135void136d3d12_forward_front_face(nir_shader *nir)137{138assert(nir->info.stage == MESA_SHADER_FRAGMENT);139140nir_variable *var = nir_variable_create(nir, nir_var_shader_in,141glsl_bool_type(),142"gl_FrontFacing");143var->data.location = VARYING_SLOT_VAR12;144var->data.interpolation = INTERP_MODE_FLAT;145146147nir_foreach_function(function, nir) {148if (function->impl) {149nir_builder b;150nir_builder_init(&b, function->impl);151152nir_foreach_block(block, function->impl) {153nir_foreach_instr_safe(instr, block) {154lower_load_face(&b, instr, var);155}156}157158nir_metadata_preserve(function->impl, nir_metadata_block_index |159nir_metadata_dominance);160}161}162}163164static void165lower_pos_read(nir_builder *b, struct nir_instr *instr,166nir_variable **depth_transform_var)167{168if (instr->type != nir_instr_type_intrinsic)169return;170171nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);172if (intr->intrinsic != nir_intrinsic_load_deref)173return;174175nir_variable *var = nir_intrinsic_get_var(intr, 0);176if (var->data.mode != nir_var_shader_in ||177var->data.location != VARYING_SLOT_POS)178return;179180b->cursor = nir_after_instr(instr);181182nir_ssa_def *pos = nir_instr_ssa_def(instr);183nir_ssa_def *depth = nir_channel(b, pos, 2);184185assert(depth_transform_var);186nir_ssa_def *depth_transform = get_state_var(b, D3D12_STATE_VAR_DEPTH_TRANSFORM,187"d3d12_DepthTransform",188glsl_vec_type(2),189depth_transform_var);190depth = nir_fmad(b, depth, nir_channel(b, depth_transform, 0),191nir_channel(b, depth_transform, 1));192193pos = nir_vector_insert_imm(b, pos, depth, 2);194195assert(intr->dest.is_ssa);196nir_ssa_def_rewrite_uses_after(&intr->dest.ssa, pos,197pos->parent_instr);198}199200void201d3d12_lower_depth_range(nir_shader *nir)202{203assert(nir->info.stage == MESA_SHADER_FRAGMENT);204nir_variable *depth_transform = NULL;205nir_foreach_function(function, nir) {206if (function->impl) {207nir_builder b;208nir_builder_init(&b, function->impl);209210nir_foreach_block(block, function->impl) {211nir_foreach_instr_safe(instr, block) {212lower_pos_read(&b, instr, &depth_transform);213}214}215216nir_metadata_preserve(function->impl, nir_metadata_block_index |217nir_metadata_dominance);218}219}220}221222static bool223is_color_output(nir_variable *var)224{225return (var->data.mode == nir_var_shader_out &&226(var->data.location == FRAG_RESULT_COLOR ||227var->data.location >= FRAG_RESULT_DATA0));228}229230static void231lower_uint_color_write(nir_builder *b, struct nir_instr *instr, bool is_signed)232{233const unsigned NUM_BITS = 8;234const unsigned bits[4] = { NUM_BITS, NUM_BITS, NUM_BITS, NUM_BITS };235236if (instr->type != nir_instr_type_intrinsic)237return;238239nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);240if (intr->intrinsic != nir_intrinsic_store_deref)241return;242243nir_variable *var = nir_intrinsic_get_var(intr, 0);244if (!is_color_output(var))245return;246247b->cursor = nir_before_instr(&intr->instr);248249nir_ssa_def *col = nir_ssa_for_src(b, intr->src[1], intr->num_components);250nir_ssa_def *def = is_signed ? nir_format_float_to_snorm(b, col, bits) :251nir_format_float_to_unorm(b, col, bits);252if (is_signed)253def = nir_bcsel(b, nir_ilt(b, def, nir_imm_int(b, 0)),254nir_iadd(b, def, nir_imm_int(b, 1 << NUM_BITS)),255def);256nir_instr_rewrite_src(&intr->instr, intr->src + 1, nir_src_for_ssa(def));257}258259void260d3d12_lower_uint_cast(nir_shader *nir, bool is_signed)261{262if (nir->info.stage != MESA_SHADER_FRAGMENT)263return;264265nir_foreach_function(function, nir) {266if (function->impl) {267nir_builder b;268nir_builder_init(&b, function->impl);269270nir_foreach_block(block, function->impl) {271nir_foreach_instr_safe(instr, block) {272lower_uint_color_write(&b, instr, is_signed);273}274}275276nir_metadata_preserve(function->impl, nir_metadata_block_index |277nir_metadata_dominance);278}279}280}281282static bool283lower_load_first_vertex(nir_builder *b, nir_instr *instr, nir_variable **first_vertex)284{285if (instr->type != nir_instr_type_intrinsic)286return false;287288nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);289290if (intr->intrinsic != nir_intrinsic_load_first_vertex)291return false;292293b->cursor = nir_before_instr(&intr->instr);294295nir_ssa_def *load = get_state_var(b, D3D12_STATE_VAR_FIRST_VERTEX, "d3d12_FirstVertex",296glsl_uint_type(), first_vertex);297nir_ssa_def_rewrite_uses(&intr->dest.ssa, load);298nir_instr_remove(instr);299300return true;301}302303bool304d3d12_lower_load_first_vertex(struct nir_shader *nir)305{306nir_variable *first_vertex = NULL;307bool progress = false;308309if (nir->info.stage != MESA_SHADER_VERTEX)310return false;311312nir_foreach_function(function, nir) {313if (function->impl) {314nir_builder b;315nir_builder_init(&b, function->impl);316317nir_foreach_block(block, function->impl) {318nir_foreach_instr_safe(instr, block) {319progress |= lower_load_first_vertex(&b, instr, &first_vertex);320}321}322323nir_metadata_preserve(function->impl, nir_metadata_block_index |324nir_metadata_dominance);325}326}327return progress;328}329330static void331invert_depth(nir_builder *b, struct nir_instr *instr)332{333if (instr->type != nir_instr_type_intrinsic)334return;335336nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);337if (intr->intrinsic != nir_intrinsic_store_deref)338return;339340nir_variable *var = nir_intrinsic_get_var(intr, 0);341if (var->data.mode != nir_var_shader_out ||342var->data.location != VARYING_SLOT_POS)343return;344345b->cursor = nir_before_instr(&intr->instr);346347nir_ssa_def *pos = nir_ssa_for_src(b, intr->src[1], 4);348nir_ssa_def *def = nir_vec4(b,349nir_channel(b, pos, 0),350nir_channel(b, pos, 1),351nir_fneg(b, nir_channel(b, pos, 2)),352nir_channel(b, pos, 3));353nir_instr_rewrite_src(&intr->instr, intr->src + 1, nir_src_for_ssa(def));354}355356/* In OpenGL the windows space depth value z_w is evaluated according to "s * z_d + b"357* with "s + (far - near) / 2" (depth clip:minus_one_to_one) [OpenGL 3.3, 2.13.1].358* When we switch the far and near value to satisfy DirectX requirements we have359* to compensate by inverting "z_d' = -z_d" with this lowering pass.360*/361void362d3d12_nir_invert_depth(nir_shader *shader)363{364if (shader->info.stage != MESA_SHADER_VERTEX &&365shader->info.stage != MESA_SHADER_GEOMETRY)366return;367368nir_foreach_function(function, shader) {369if (function->impl) {370nir_builder b;371nir_builder_init(&b, function->impl);372373nir_foreach_block(block, function->impl) {374nir_foreach_instr_safe(instr, block) {375invert_depth(&b, instr);376}377}378379nir_metadata_preserve(function->impl, nir_metadata_block_index |380nir_metadata_dominance);381}382}383}384385386/**387* Lower State Vars:388*389* All uniforms related to internal D3D12 variables are390* condensed into a UBO that is appended at the end of the391* current ones.392*/393394static unsigned395get_state_var_offset(struct d3d12_shader *shader, enum d3d12_state_var var)396{397for (unsigned i = 0; i < shader->num_state_vars; ++i) {398if (shader->state_vars[i].var == var)399return shader->state_vars[i].offset;400}401402unsigned offset = shader->state_vars_size;403shader->state_vars[shader->num_state_vars].offset = offset;404shader->state_vars[shader->num_state_vars].var = var;405shader->state_vars_size += 4; /* Use 4-words slots no matter the variable size */406shader->num_state_vars++;407408return offset;409}410411static bool412lower_instr(nir_intrinsic_instr *instr, nir_builder *b,413struct d3d12_shader *shader, unsigned binding)414{415nir_variable *variable = NULL;416nir_deref_instr *deref = NULL;417418b->cursor = nir_before_instr(&instr->instr);419420if (instr->intrinsic == nir_intrinsic_load_uniform) {421nir_foreach_variable_with_modes(var, b->shader, nir_var_uniform) {422if (var->data.driver_location == nir_intrinsic_base(instr)) {423variable = var;424break;425}426}427} else if (instr->intrinsic == nir_intrinsic_load_deref) {428deref = nir_src_as_deref(instr->src[0]);429variable = nir_intrinsic_get_var(instr, 0);430}431432if (variable == NULL ||433variable->num_state_slots != 1 ||434variable->state_slots[0].tokens[0] != STATE_INTERNAL_DRIVER)435return false;436437enum d3d12_state_var var = variable->state_slots[0].tokens[1];438nir_ssa_def *ubo_idx = nir_imm_int(b, binding);439nir_ssa_def *ubo_offset = nir_imm_int(b, get_state_var_offset(shader, var) * 4);440nir_ssa_def *load =441nir_load_ubo(b, instr->num_components, instr->dest.ssa.bit_size,442ubo_idx, ubo_offset,443.align_mul = instr->dest.ssa.bit_size / 8,444.align_offset = 0,445.range_base = 0,446.range = ~0,447);448449nir_ssa_def_rewrite_uses(&instr->dest.ssa, load);450451/* Remove the old load_* instruction and any parent derefs */452nir_instr_remove(&instr->instr);453for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {454/* If anyone is using this deref, leave it alone */455assert(d->dest.is_ssa);456if (!list_is_empty(&d->dest.ssa.uses))457break;458459nir_instr_remove(&d->instr);460}461462return true;463}464465bool466d3d12_lower_state_vars(nir_shader *nir, struct d3d12_shader *shader)467{468bool progress = false;469470/* The state var UBO is added after all the other UBOs if it already471* exists it will be replaced by using the same binding.472* In the event there are no other UBO's, use binding slot 1 to473* be consistent with other non-default UBO's */474unsigned binding = MAX2(nir->info.num_ubos, 1);475476nir_foreach_variable_with_modes_safe(var, nir, nir_var_uniform) {477if (var->num_state_slots == 1 &&478var->state_slots[0].tokens[0] == STATE_INTERNAL_DRIVER) {479if (var->data.mode == nir_var_mem_ubo) {480binding = var->data.binding;481}482}483}484485nir_foreach_function(function, nir) {486if (function->impl) {487nir_builder builder;488nir_builder_init(&builder, function->impl);489nir_foreach_block(block, function->impl) {490nir_foreach_instr_safe(instr, block) {491if (instr->type == nir_instr_type_intrinsic)492progress |= lower_instr(nir_instr_as_intrinsic(instr),493&builder,494shader,495binding);496}497}498499nir_metadata_preserve(function->impl, nir_metadata_block_index |500nir_metadata_dominance);501}502}503504if (progress) {505assert(shader->num_state_vars > 0);506507shader->state_vars_used = true;508509/* Remove state variables */510nir_foreach_variable_with_modes_safe(var, nir, nir_var_uniform) {511if (var->num_state_slots == 1 &&512var->state_slots[0].tokens[0] == STATE_INTERNAL_DRIVER) {513exec_node_remove(&var->node);514nir->num_uniforms--;515}516}517518const gl_state_index16 tokens[STATE_LENGTH] = { STATE_INTERNAL_DRIVER };519const struct glsl_type *type = glsl_array_type(glsl_vec4_type(),520shader->state_vars_size / 4, 0);521nir_variable *ubo = nir_variable_create(nir, nir_var_mem_ubo, type,522"d3d12_state_vars");523if (binding >= nir->info.num_ubos)524nir->info.num_ubos = binding + 1;525ubo->data.binding = binding;526ubo->num_state_slots = 1;527ubo->state_slots = ralloc_array(ubo, nir_state_slot, 1);528memcpy(ubo->state_slots[0].tokens, tokens,529sizeof(ubo->state_slots[0].tokens));530531struct glsl_struct_field field = {532.type = type,533.name = "data",534.location = -1,535};536ubo->interface_type =537glsl_interface_type(&field, 1, GLSL_INTERFACE_PACKING_STD430,538false, "__d3d12_state_vars_interface");539}540541return progress;542}543544static bool545lower_bool_input_filter(const nir_instr *instr,546UNUSED const void *_options)547{548if (instr->type != nir_instr_type_intrinsic)549return false;550551nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);552if (intr->intrinsic == nir_intrinsic_load_front_face)553return true;554555if (intr->intrinsic == nir_intrinsic_load_deref) {556nir_deref_instr *deref = nir_instr_as_deref(intr->src[0].ssa->parent_instr);557nir_variable *var = nir_deref_instr_get_variable(deref);558return var->data.mode == nir_var_shader_in &&559glsl_get_base_type(var->type) == GLSL_TYPE_BOOL;560}561562return false;563}564565static nir_ssa_def *566lower_bool_input_impl(nir_builder *b, nir_instr *instr,567UNUSED void *_options)568{569nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);570571if (intr->intrinsic == nir_intrinsic_load_deref) {572nir_deref_instr *deref = nir_instr_as_deref(intr->src[0].ssa->parent_instr);573nir_variable *var = nir_deref_instr_get_variable(deref);574575/* rewrite var->type */576var->type = glsl_vector_type(GLSL_TYPE_UINT,577glsl_get_vector_elements(var->type));578deref->type = var->type;579}580581intr->dest.ssa.bit_size = 32;582return nir_i2b1(b, &intr->dest.ssa);583}584585bool586d3d12_lower_bool_input(struct nir_shader *s)587{588return nir_shader_lower_instructions(s, lower_bool_input_filter,589lower_bool_input_impl, NULL);590}591592void593d3d12_add_missing_dual_src_target(struct nir_shader *s,594unsigned missing_mask)595{596assert(missing_mask != 0);597nir_builder b;598nir_function_impl *impl = nir_shader_get_entrypoint(s);599nir_builder_init(&b, impl);600b.cursor = nir_before_cf_list(&impl->body);601602nir_ssa_def *zero = nir_imm_zero(&b, 4, 32);603for (unsigned i = 0; i < 2; ++i) {604605if (!(missing_mask & (1u << i)))606continue;607608const char *name = i == 0 ? "gl_FragData[0]" :609"gl_SecondaryFragDataEXT[0]";610nir_variable *out = nir_variable_create(s, nir_var_shader_out,611glsl_vec4_type(), name);612out->data.location = FRAG_RESULT_DATA0;613out->data.driver_location = i;614out->data.index = i;615616nir_store_var(&b, out, zero, 0xf);617}618nir_metadata_preserve(impl, nir_metadata_block_index |619nir_metadata_dominance);620}621622static bool623fix_io_uint_type(struct nir_shader *s, nir_variable_mode modes, int slot)624{625nir_variable *fixed_var = NULL;626nir_foreach_variable_with_modes(var, s, modes) {627if (var->data.location == slot) {628var->type = glsl_uint_type();629fixed_var = var;630break;631}632}633634assert(fixed_var);635636nir_foreach_function(function, s) {637if (function->impl) {638nir_foreach_block(block, function->impl) {639nir_foreach_instr_safe(instr, block) {640if (instr->type == nir_instr_type_deref) {641nir_deref_instr *deref = nir_instr_as_deref(instr);642if (deref->var == fixed_var)643deref->type = fixed_var->type;644}645}646}647}648}649return true;650}651652bool653d3d12_fix_io_uint_type(struct nir_shader *s, uint64_t in_mask, uint64_t out_mask)654{655if (!(s->info.outputs_written & out_mask) &&656!(s->info.inputs_read & in_mask))657return false;658659bool progress = false;660661while (in_mask) {662int slot = u_bit_scan64(&in_mask);663progress |= (s->info.inputs_read & (1ull << slot)) &&664fix_io_uint_type(s, nir_var_shader_in, slot);665}666667while (out_mask) {668int slot = u_bit_scan64(&out_mask);669progress |= (s->info.outputs_written & (1ull << slot)) &&670fix_io_uint_type(s, nir_var_shader_out, slot);671}672673return progress;674}675676static bool677lower_load_ubo_packed_filter(const nir_instr *instr,678UNUSED const void *_options) {679if (instr->type != nir_instr_type_intrinsic)680return false;681682nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);683684return intr->intrinsic == nir_intrinsic_load_ubo;685}686687static nir_ssa_def *688lower_load_ubo_packed_impl(nir_builder *b, nir_instr *instr,689UNUSED void *_options) {690nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);691692nir_ssa_def *buffer = intr->src[0].ssa;693nir_ssa_def *offset = intr->src[1].ssa;694695nir_ssa_def *result =696build_load_ubo_dxil(b, buffer,697offset,698nir_dest_num_components(intr->dest),699nir_dest_bit_size(intr->dest));700return result;701}702703bool704nir_lower_packed_ubo_loads(nir_shader *nir) {705return nir_shader_lower_instructions(nir,706lower_load_ubo_packed_filter,707lower_load_ubo_packed_impl,708NULL);709}710711void712d3d12_lower_primitive_id(nir_shader *shader)713{714nir_builder b;715nir_function_impl *impl = nir_shader_get_entrypoint(shader);716nir_ssa_def *primitive_id;717nir_builder_init(&b, impl);718719nir_variable *primitive_id_var = nir_variable_create(shader, nir_var_shader_out,720glsl_uint_type(), "primitive_id");721primitive_id_var->data.location = VARYING_SLOT_PRIMITIVE_ID;722primitive_id_var->data.interpolation = INTERP_MODE_FLAT;723724nir_foreach_block(block, impl) {725b.cursor = nir_before_block(block);726primitive_id = nir_load_primitive_id(&b);727728nir_foreach_instr_safe(instr, block) {729if (instr->type != nir_instr_type_intrinsic ||730nir_instr_as_intrinsic(instr)->intrinsic != nir_intrinsic_emit_vertex)731continue;732733b.cursor = nir_before_instr(instr);734nir_store_var(&b, primitive_id_var, primitive_id, 0x1);735}736}737738nir_metadata_preserve(impl, 0);739}740741static void742lower_triangle_strip_store(nir_builder *b, nir_intrinsic_instr *intr,743nir_variable *vertex_count_var,744nir_variable **varyings)745{746/**747* tmp_varying[slot][min(vertex_count, 2)] = src748*/749nir_ssa_def *vertex_count = nir_load_var(b, vertex_count_var);750nir_ssa_def *index = nir_imin(b, vertex_count, nir_imm_int(b, 2));751nir_variable *var = nir_intrinsic_get_var(intr, 0);752753if (var->data.mode != nir_var_shader_out)754return;755756nir_deref_instr *deref = nir_build_deref_array(b, nir_build_deref_var(b, varyings[var->data.location]), index);757nir_ssa_def *value = nir_ssa_for_src(b, intr->src[1], intr->num_components);758nir_store_deref(b, deref, value, 0xf);759nir_instr_remove(&intr->instr);760}761762static void763lower_triangle_strip_emit_vertex(nir_builder *b, nir_intrinsic_instr *intr,764nir_variable *vertex_count_var,765nir_variable **varyings,766nir_variable **out_varyings)767{768// TODO xfb + flat shading + last_pv769/**770* if (vertex_count >= 2) {771* for (i = 0; i < 3; i++) {772* foreach(slot)773* out[slot] = tmp_varying[slot][i];774* EmitVertex();775* }776* EndPrimitive();777* foreach(slot)778* tmp_varying[slot][vertex_count % 2] = tmp_varying[slot][2];779* }780* vertex_count++;781*/782783nir_ssa_def *two = nir_imm_int(b, 2);784nir_ssa_def *vertex_count = nir_load_var(b, vertex_count_var);785nir_ssa_def *count_cmp = nir_uge(b, vertex_count, two);786nir_if *count_check = nir_push_if(b, count_cmp);787788for (int j = 0; j < 3; ++j) {789for (int i = 0; i < VARYING_SLOT_MAX; ++i) {790if (!varyings[i])791continue;792nir_copy_deref(b, nir_build_deref_var(b, out_varyings[i]),793nir_build_deref_array_imm(b, nir_build_deref_var(b, varyings[i]), j));794}795nir_emit_vertex(b, 0);796}797798for (int i = 0; i < VARYING_SLOT_MAX; ++i) {799if (!varyings[i])800continue;801nir_copy_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, varyings[i]), nir_umod(b, vertex_count, two)),802nir_build_deref_array(b, nir_build_deref_var(b, varyings[i]), two));803}804805nir_end_primitive(b, .stream_id = 0);806807nir_pop_if(b, count_check);808809vertex_count = nir_iadd(b, vertex_count, nir_imm_int(b, 1));810nir_store_var(b, vertex_count_var, vertex_count, 0x1);811812nir_instr_remove(&intr->instr);813}814815static void816lower_triangle_strip_end_primitive(nir_builder *b, nir_intrinsic_instr *intr,817nir_variable *vertex_count_var)818{819/**820* vertex_count = 0;821*/822nir_store_var(b, vertex_count_var, nir_imm_int(b, 0), 0x1);823nir_instr_remove(&intr->instr);824}825826void827d3d12_lower_triangle_strip(nir_shader *shader)828{829nir_builder b;830nir_function_impl *impl = nir_shader_get_entrypoint(shader);831nir_variable *tmp_vars[VARYING_SLOT_MAX] = {0};832nir_variable *out_vars[VARYING_SLOT_MAX] = {0};833nir_builder_init(&b, impl);834835shader->info.gs.vertices_out = (shader->info.gs.vertices_out - 2) * 3;836837nir_variable *vertex_count_var =838nir_local_variable_create(impl, glsl_uint_type(), "vertex_count");839840nir_block *first = nir_start_block(impl);841b.cursor = nir_before_block(first);842nir_foreach_variable_with_modes(var, shader, nir_var_shader_out) {843const struct glsl_type *type = glsl_array_type(var->type, 3, 0);844tmp_vars[var->data.location] = nir_local_variable_create(impl, type, "tmp_var");845out_vars[var->data.location] = var;846}847nir_store_var(&b, vertex_count_var, nir_imm_int(&b, 0), 1);848849nir_foreach_block(block, impl) {850nir_foreach_instr_safe(instr, block) {851if (instr->type != nir_instr_type_intrinsic)852continue;853854nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);855switch (intrin->intrinsic) {856case nir_intrinsic_store_deref:857b.cursor = nir_before_instr(instr);858lower_triangle_strip_store(&b, intrin, vertex_count_var, tmp_vars);859break;860case nir_intrinsic_emit_vertex_with_counter:861case nir_intrinsic_emit_vertex:862b.cursor = nir_before_instr(instr);863lower_triangle_strip_emit_vertex(&b, intrin, vertex_count_var,864tmp_vars, out_vars);865break;866case nir_intrinsic_end_primitive:867case nir_intrinsic_end_primitive_with_counter:868b.cursor = nir_before_instr(instr);869lower_triangle_strip_end_primitive(&b, intrin, vertex_count_var);870break;871default:872break;873}874}875}876877nir_metadata_preserve(impl, 0);878NIR_PASS_V(shader, nir_lower_var_copies);879}880881882