Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_gs_variant.cpp
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* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* 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 NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include "d3d12_compiler.h"24#include "d3d12_context.h"25#include "d3d12_debug.h"26#include "d3d12_screen.h"27#include "nir_to_dxil.h"2829#include "nir.h"30#include "compiler/nir/nir_builder.h"31#include "compiler/nir/nir_builtin_builder.h"3233#include "util/u_memory.h"34#include "util/u_simple_shaders.h"3536static nir_ssa_def *37nir_cull_face(nir_builder *b, nir_variable *vertices, bool ccw)38{39nir_ssa_def *v0 =40nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 0)));41nir_ssa_def *v1 =42nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 1)));43nir_ssa_def *v2 =44nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, vertices), nir_imm_int(b, 2)));4546nir_ssa_def *dir = nir_fdot(b, nir_cross4(b, nir_fsub(b, v1, v0),47nir_fsub(b, v2, v0)),48nir_imm_vec4(b, 0.0, 0.0, -1.0, 0.0));49if (ccw)50return nir_fge(b, nir_imm_int(b, 0), dir);51else52return nir_flt(b, nir_imm_int(b, 0), dir);53}5455static d3d12_shader_selector*56d3d12_make_passthrough_gs(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)57{58struct d3d12_shader_selector *gs;59uint64_t varyings = key->varyings.mask;60nir_shader *nir;61struct pipe_shader_state templ;6263nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY,64dxil_get_nir_compiler_options(),65"passthrough");6667nir = b.shader;68nir->info.inputs_read = varyings;69nir->info.outputs_written = varyings;70nir->info.gs.input_primitive = GL_POINTS;71nir->info.gs.output_primitive = GL_POINTS;72nir->info.gs.vertices_in = 1;73nir->info.gs.vertices_out = 1;74nir->info.gs.invocations = 1;75nir->info.gs.active_stream_mask = 1;7677/* Copy inputs to outputs. */78while (varyings) {79nir_variable *in, *out;80char tmp[100];81const int i = u_bit_scan64(&varyings);8283snprintf(tmp, ARRAY_SIZE(tmp), "in_%d", key->varyings.vars[i].driver_location);84in = nir_variable_create(nir,85nir_var_shader_in,86glsl_array_type(key->varyings.vars[i].type, 1, false),87tmp);88in->data.location = i;89in->data.driver_location = key->varyings.vars[i].driver_location;90in->data.interpolation = key->varyings.vars[i].interpolation;9192snprintf(tmp, ARRAY_SIZE(tmp), "out_%d", key->varyings.vars[i].driver_location);93out = nir_variable_create(nir,94nir_var_shader_out,95key->varyings.vars[i].type,96tmp);97out->data.location = i;98out->data.driver_location = key->varyings.vars[i].driver_location;99out->data.interpolation = key->varyings.vars[i].interpolation;100101nir_deref_instr *in_value = nir_build_deref_array(&b, nir_build_deref_var(&b, in),102nir_imm_int(&b, 0));103nir_copy_deref(&b, nir_build_deref_var(&b, out), in_value);104}105106nir_emit_vertex(&b, 0);107nir_end_primitive(&b, 0);108109NIR_PASS_V(nir, nir_lower_var_copies);110nir_validate_shader(nir, "in d3d12_create_passthrough_gs");111112templ.type = PIPE_SHADER_IR_NIR;113templ.ir.nir = nir;114templ.stream_output.num_outputs = 0;115116gs = d3d12_create_shader(ctx, PIPE_SHADER_GEOMETRY, &templ);117118return gs;119}120121struct emit_primitives_context122{123struct d3d12_context *ctx;124nir_builder b;125126unsigned num_vars;127nir_variable *in[MAX_VARYING];128nir_variable *out[MAX_VARYING];129nir_variable *front_facing_var;130131nir_loop *loop;132nir_deref_instr *loop_index_deref;133nir_ssa_def *loop_index;134nir_ssa_def *edgeflag_cmp;135nir_ssa_def *front_facing;136};137138static bool139d3d12_begin_emit_primitives_gs(struct emit_primitives_context *emit_ctx,140struct d3d12_context *ctx,141struct d3d12_gs_variant_key *key,142uint16_t output_primitive,143unsigned vertices_out)144{145nir_builder *b = &emit_ctx->b;146nir_variable *edgeflag_var = NULL;147nir_variable *pos_var = NULL;148uint64_t varyings = key->varyings.mask;149150emit_ctx->ctx = ctx;151152emit_ctx->b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY,153dxil_get_nir_compiler_options(),154"edgeflags");155156nir_shader *nir = b->shader;157nir->info.inputs_read = varyings;158nir->info.outputs_written = varyings;159nir->info.gs.input_primitive = GL_TRIANGLES;160nir->info.gs.output_primitive = output_primitive;161nir->info.gs.vertices_in = 3;162nir->info.gs.vertices_out = vertices_out;163nir->info.gs.invocations = 1;164nir->info.gs.active_stream_mask = 1;165166while (varyings) {167char tmp[100];168const int i = u_bit_scan64(&varyings);169170snprintf(tmp, ARRAY_SIZE(tmp), "in_%d", emit_ctx->num_vars);171emit_ctx->in[emit_ctx->num_vars] = nir_variable_create(nir,172nir_var_shader_in,173glsl_array_type(key->varyings.vars[i].type, 3, 0),174tmp);175emit_ctx->in[emit_ctx->num_vars]->data.location = i;176emit_ctx->in[emit_ctx->num_vars]->data.driver_location = key->varyings.vars[i].driver_location;177emit_ctx->in[emit_ctx->num_vars]->data.interpolation = key->varyings.vars[i].interpolation;178179/* Don't create an output for the edge flag variable */180if (i == VARYING_SLOT_EDGE) {181edgeflag_var = emit_ctx->in[emit_ctx->num_vars];182continue;183} else if (i == VARYING_SLOT_POS) {184pos_var = emit_ctx->in[emit_ctx->num_vars];185}186187snprintf(tmp, ARRAY_SIZE(tmp), "out_%d", emit_ctx->num_vars);188emit_ctx->out[emit_ctx->num_vars] = nir_variable_create(nir,189nir_var_shader_out,190key->varyings.vars[i].type,191tmp);192emit_ctx->out[emit_ctx->num_vars]->data.location = i;193emit_ctx->out[emit_ctx->num_vars]->data.driver_location = key->varyings.vars[i].driver_location;194emit_ctx->out[emit_ctx->num_vars]->data.interpolation = key->varyings.vars[i].interpolation;195196emit_ctx->num_vars++;197}198199if (key->has_front_face) {200emit_ctx->front_facing_var = nir_variable_create(nir,201nir_var_shader_out,202glsl_uint_type(),203"gl_FrontFacing");204emit_ctx->front_facing_var->data.location = VARYING_SLOT_VAR12;205emit_ctx->front_facing_var->data.driver_location = emit_ctx->num_vars;206emit_ctx->front_facing_var->data.interpolation = INTERP_MODE_FLAT;207}208209/* Temporary variable "loop_index" to loop over input vertices */210nir_function_impl *impl = nir_shader_get_entrypoint(nir);211nir_variable *loop_index_var =212nir_local_variable_create(impl, glsl_uint_type(), "loop_index");213emit_ctx->loop_index_deref = nir_build_deref_var(b, loop_index_var);214nir_store_deref(b, emit_ctx->loop_index_deref, nir_imm_int(b, 0), 1);215216nir_ssa_def *diagonal_vertex = NULL;217if (key->edge_flag_fix) {218nir_ssa_def *prim_id = nir_load_primitive_id(b);219nir_ssa_def *odd = nir_build_alu(b, nir_op_imod,220prim_id,221nir_imm_int(b, 2),222NULL, NULL);223diagonal_vertex = nir_bcsel(b, nir_i2b(b, odd),224nir_imm_int(b, 2),225nir_imm_int(b, 1));226}227228if (key->cull_mode != PIPE_FACE_NONE || key->has_front_face) {229if (key->cull_mode == PIPE_FACE_BACK)230emit_ctx->edgeflag_cmp = nir_cull_face(b, pos_var, key->front_ccw);231else if (key->cull_mode == PIPE_FACE_FRONT)232emit_ctx->edgeflag_cmp = nir_cull_face(b, pos_var, !key->front_ccw);233234if (key->has_front_face) {235if (key->cull_mode == PIPE_FACE_BACK)236emit_ctx->front_facing = emit_ctx->edgeflag_cmp;237else238emit_ctx->front_facing = nir_cull_face(b, pos_var, key->front_ccw);239emit_ctx->front_facing = nir_i2i32(b, emit_ctx->front_facing);240}241}242243/**244* while {245* if (loop_index >= 3)246* break;247*/248emit_ctx->loop = nir_push_loop(b);249250emit_ctx->loop_index = nir_load_deref(b, emit_ctx->loop_index_deref);251nir_ssa_def *cmp = nir_ige(b, emit_ctx->loop_index,252nir_imm_int(b, 3));253nir_if *loop_check = nir_push_if(b, cmp);254nir_jump(b, nir_jump_break);255nir_pop_if(b, loop_check);256257if (edgeflag_var) {258nir_ssa_def *edge_flag =259nir_load_deref(b, nir_build_deref_array(b, nir_build_deref_var(b, edgeflag_var), emit_ctx->loop_index));260nir_ssa_def *is_edge = nir_feq(b, nir_channel(b, edge_flag, 0), nir_imm_float(b, 1.0));261if (emit_ctx->edgeflag_cmp)262emit_ctx->edgeflag_cmp = nir_iand(b, emit_ctx->edgeflag_cmp, is_edge);263else264emit_ctx->edgeflag_cmp = is_edge;265}266267if (key->edge_flag_fix) {268nir_ssa_def *is_edge = nir_ine(b, emit_ctx->loop_index, diagonal_vertex);269if (emit_ctx->edgeflag_cmp)270emit_ctx->edgeflag_cmp = nir_iand(b, emit_ctx->edgeflag_cmp, is_edge);271else272emit_ctx->edgeflag_cmp = is_edge;273}274275return true;276}277278static struct d3d12_shader_selector *279d3d12_finish_emit_primitives_gs(struct emit_primitives_context *emit_ctx, bool end_primitive)280{281struct pipe_shader_state templ;282nir_builder *b = &emit_ctx->b;283nir_shader *nir = b->shader;284285/**286* loop_index++;287* }288*/289nir_store_deref(b, emit_ctx->loop_index_deref, nir_iadd_imm(b, emit_ctx->loop_index, 1), 1);290nir_pop_loop(b, emit_ctx->loop);291292if (end_primitive)293nir_end_primitive(b, 0);294295nir_validate_shader(nir, "in d3d12_lower_edge_flags");296297NIR_PASS_V(nir, nir_lower_var_copies);298299templ.type = PIPE_SHADER_IR_NIR;300templ.ir.nir = nir;301templ.stream_output.num_outputs = 0;302303return d3d12_create_shader(emit_ctx->ctx, PIPE_SHADER_GEOMETRY, &templ);304}305306static d3d12_shader_selector*307d3d12_emit_points(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)308{309struct emit_primitives_context emit_ctx = {0};310nir_builder *b = &emit_ctx.b;311312d3d12_begin_emit_primitives_gs(&emit_ctx, ctx, key, GL_POINTS, 3);313314/**315* if (edge_flag)316* out_position = in_position;317* else318* out_position = vec4(-2.0, -2.0, 0.0, 1.0); // Invalid position319*320* [...] // Copy other variables321*322* EmitVertex();323*/324for (unsigned i = 0; i < emit_ctx.num_vars; ++i) {325nir_ssa_def *index = (key->flat_varyings & (1ull << emit_ctx.in[i]->data.location)) ?326nir_imm_int(b, (key->flatshade_first ? 0 : 2)) : emit_ctx.loop_index;327nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index);328if (emit_ctx.in[i]->data.location == VARYING_SLOT_POS && emit_ctx.edgeflag_cmp) {329nir_if *edge_check = nir_push_if(b, emit_ctx.edgeflag_cmp);330nir_copy_deref(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value);331nir_if *edge_else = nir_push_else(b, edge_check);332nir_store_deref(b, nir_build_deref_var(b, emit_ctx.out[i]),333nir_imm_vec4(b, -2.0, -2.0, 0.0, 1.0), 0xf);334nir_pop_if(b, edge_else);335} else {336nir_copy_deref(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value);337}338}339if (key->has_front_face)340nir_store_var(b, emit_ctx.front_facing_var, emit_ctx.front_facing, 0x1);341nir_emit_vertex(b, 0);342343return d3d12_finish_emit_primitives_gs(&emit_ctx, false);344}345346static d3d12_shader_selector*347d3d12_emit_lines(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)348{349struct emit_primitives_context emit_ctx = {0};350nir_builder *b = &emit_ctx.b;351352d3d12_begin_emit_primitives_gs(&emit_ctx, ctx, key, GL_LINE_STRIP, 6);353354nir_ssa_def *next_index = nir_imod(b, nir_iadd_imm(b, emit_ctx.loop_index, 1), nir_imm_int(b, 3));355356/* First vertex */357for (unsigned i = 0; i < emit_ctx.num_vars; ++i) {358nir_ssa_def *index = (key->flat_varyings & (1ull << emit_ctx.in[i]->data.location)) ?359nir_imm_int(b, (key->flatshade_first ? 0 : 2)) : emit_ctx.loop_index;360nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index);361nir_copy_deref(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value);362}363if (key->has_front_face)364nir_store_var(b, emit_ctx.front_facing_var, emit_ctx.front_facing, 0x1);365nir_emit_vertex(b, 0);366367/* Second vertex. If not an edge, use same position as first vertex */368for (unsigned i = 0; i < emit_ctx.num_vars; ++i) {369nir_ssa_def *index = next_index;370if (emit_ctx.in[i]->data.location == VARYING_SLOT_POS)371index = nir_bcsel(b, emit_ctx.edgeflag_cmp, next_index, emit_ctx.loop_index);372else if (key->flat_varyings & (1ull << emit_ctx.in[i]->data.location))373index = nir_imm_int(b, 2);374nir_copy_deref(b, nir_build_deref_var(b, emit_ctx.out[i]),375nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index));376}377if (key->has_front_face)378nir_store_var(b, emit_ctx.front_facing_var, emit_ctx.front_facing, 0x1);379nir_emit_vertex(b, 0);380381nir_end_primitive(b, 0);382383return d3d12_finish_emit_primitives_gs(&emit_ctx, false);384}385386static d3d12_shader_selector*387d3d12_emit_triangles(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)388{389struct emit_primitives_context emit_ctx = {0};390nir_builder *b = &emit_ctx.b;391392d3d12_begin_emit_primitives_gs(&emit_ctx, ctx, key, GL_TRIANGLE_STRIP, 3);393394/**395* [...] // Copy variables396*397* EmitVertex();398*/399400nir_ssa_def *incr = NULL;401402if (key->provoking_vertex > 0)403incr = nir_imm_int(b, key->provoking_vertex);404else405incr = nir_imm_int(b, 3);406407if (key->alternate_tri) {408nir_ssa_def *odd = nir_imod(b, nir_load_primitive_id(b), nir_imm_int(b, 2));409incr = nir_isub(b, incr, odd);410}411412assert(incr != NULL);413nir_ssa_def *index = nir_imod(b, nir_iadd(b, emit_ctx.loop_index, incr), nir_imm_int(b, 3));414for (unsigned i = 0; i < emit_ctx.num_vars; ++i) {415nir_deref_instr *in_value = nir_build_deref_array(b, nir_build_deref_var(b, emit_ctx.in[i]), index);416nir_copy_deref(b, nir_build_deref_var(b, emit_ctx.out[i]), in_value);417}418nir_emit_vertex(b, 0);419420return d3d12_finish_emit_primitives_gs(&emit_ctx, true);421}422423static uint32_t424hash_gs_variant_key(const void *key)425{426return _mesa_hash_data(key, sizeof(struct d3d12_gs_variant_key));427}428429static bool430equals_gs_variant_key(const void *a, const void *b)431{432return memcmp(a, b, sizeof(struct d3d12_gs_variant_key)) == 0;433}434435void436d3d12_gs_variant_cache_init(struct d3d12_context *ctx)437{438ctx->gs_variant_cache = _mesa_hash_table_create(NULL, NULL, equals_gs_variant_key);439}440441static void442delete_entry(struct hash_entry *entry)443{444d3d12_shader_free((d3d12_shader_selector *)entry->data);445}446447void448d3d12_gs_variant_cache_destroy(struct d3d12_context *ctx)449{450_mesa_hash_table_destroy(ctx->gs_variant_cache, delete_entry);451}452453static struct d3d12_shader_selector *454create_geometry_shader_variant(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)455{456d3d12_shader_selector *gs = NULL;457458if (key->passthrough)459gs = d3d12_make_passthrough_gs(ctx, key);460else if (key->provoking_vertex > 0 || key->alternate_tri)461gs = d3d12_emit_triangles(ctx, key);462else if (key->fill_mode == PIPE_POLYGON_MODE_POINT)463gs = d3d12_emit_points(ctx, key);464else if (key->fill_mode == PIPE_POLYGON_MODE_LINE)465gs = d3d12_emit_lines(ctx, key);466467if (gs) {468gs->is_gs_variant = true;469gs->gs_key = *key;470}471472return gs;473}474475d3d12_shader_selector *476d3d12_get_gs_variant(struct d3d12_context *ctx, struct d3d12_gs_variant_key *key)477{478uint32_t hash = hash_gs_variant_key(key);479struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->gs_variant_cache,480hash, key);481if (!entry) {482d3d12_shader_selector *gs = create_geometry_shader_variant(ctx, key);483entry = _mesa_hash_table_insert_pre_hashed(ctx->gs_variant_cache,484hash, &gs->gs_key, gs);485assert(entry);486}487488return (d3d12_shader_selector *)entry->data;489}490491492