Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_lower_point_sprite.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* 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 "nir.h"24#include "nir_builder.h"25#include "d3d12_compiler.h"26#include "d3d12_nir_passes.h"27#include "dxil_nir.h"28#include "program/prog_statevars.h"2930struct lower_state {31nir_variable *uniform; /* (1/w, 1/h, pt_sz, max_sz) */32nir_variable *pos_out;33nir_variable *psiz_out;34nir_variable *point_coord_out[9];35unsigned num_point_coords;36nir_variable *varying_out[VARYING_SLOT_MAX];3738nir_ssa_def *point_dir_imm[4];39nir_ssa_def *point_coord_imm[4];4041/* Current point primitive */42nir_ssa_def *point_pos;43nir_ssa_def *point_size;44nir_ssa_def *varying[VARYING_SLOT_MAX];45unsigned varying_write_mask[VARYING_SLOT_MAX];4647bool sprite_origin_lower_left;48bool point_size_per_vertex;49bool aa_point;50};5152static void53find_outputs(nir_shader *shader, struct lower_state *state)54{55nir_foreach_variable_with_modes(var, shader, nir_var_shader_out) {56switch (var->data.location) {57case VARYING_SLOT_POS:58state->pos_out = var;59break;60case VARYING_SLOT_PSIZ:61state->psiz_out = var;62break;63default:64state->varying_out[var->data.location] = var;65break;66}67}68}6970static nir_ssa_def *71get_point_dir(nir_builder *b, struct lower_state *state, unsigned i)72{73if (state->point_dir_imm[0] == NULL) {74state->point_dir_imm[0] = nir_imm_vec2(b, -1, -1);75state->point_dir_imm[1] = nir_imm_vec2(b, -1, 1);76state->point_dir_imm[2] = nir_imm_vec2(b, 1, -1);77state->point_dir_imm[3] = nir_imm_vec2(b, 1, 1);78}7980return state->point_dir_imm[i];81}8283static nir_ssa_def *84get_point_coord(nir_builder *b, struct lower_state *state, unsigned i)85{86if (state->point_coord_imm[0] == NULL) {87if (state->sprite_origin_lower_left) {88state->point_coord_imm[0] = nir_imm_vec4(b, 0, 0, 0, 1);89state->point_coord_imm[1] = nir_imm_vec4(b, 0, 1, 0, 1);90state->point_coord_imm[2] = nir_imm_vec4(b, 1, 0, 0, 1);91state->point_coord_imm[3] = nir_imm_vec4(b, 1, 1, 0, 1);92} else {93state->point_coord_imm[0] = nir_imm_vec4(b, 0, 1, 0, 1);94state->point_coord_imm[1] = nir_imm_vec4(b, 0, 0, 0, 1);95state->point_coord_imm[2] = nir_imm_vec4(b, 1, 1, 0, 1);96state->point_coord_imm[3] = nir_imm_vec4(b, 1, 0, 0, 1);97}98}99100return state->point_coord_imm[i];101}102103/**104* scaled_point_size = pointSize * pos.w * ViewportSizeRcp105*/106static void107get_scaled_point_size(nir_builder *b, struct lower_state *state,108nir_ssa_def **x, nir_ssa_def **y)109{110/* State uniform contains: (1/ViewportWidth, 1/ViewportHeight, PointSize, MaxPointSize) */111nir_ssa_def *uniform = nir_load_var(b, state->uniform);112nir_ssa_def *point_size = state->point_size;113114/* clamp point-size to valid range */115if (point_size && state->point_size_per_vertex) {116point_size = nir_fmax(b, point_size, nir_imm_float(b, 1.0f));117point_size = nir_fmin(b, point_size, nir_imm_float(b, D3D12_MAX_POINT_SIZE));118} else {119/* Use static point size (from uniform) if the shader output was not set */120point_size = nir_channel(b, uniform, 2);121}122123point_size = nir_fmul(b, point_size, nir_channel(b, state->point_pos, 3));124*x = nir_fmul(b, point_size, nir_channel(b, uniform, 0));125*y = nir_fmul(b, point_size, nir_channel(b, uniform, 1));126}127128static bool129lower_store(nir_intrinsic_instr *instr, nir_builder *b, struct lower_state *state)130{131nir_deref_instr *deref = nir_src_as_deref(instr->src[0]);132if (nir_deref_mode_is(deref, nir_var_shader_out)) {133nir_variable *var = nir_deref_instr_get_variable(deref);134135switch (var->data.location) {136case VARYING_SLOT_POS:137state->point_pos = instr->src[1].ssa;138break;139case VARYING_SLOT_PSIZ:140state->point_size = instr->src[1].ssa;141break;142default:143state->varying[var->data.location] = instr->src[1].ssa;144state->varying_write_mask[var->data.location] = nir_intrinsic_write_mask(instr);145break;146}147148nir_instr_remove(&instr->instr);149return true;150}151152return false;153}154155static bool156lower_emit_vertex(nir_intrinsic_instr *instr, nir_builder *b, struct lower_state *state)157{158unsigned stream_id = nir_intrinsic_stream_id(instr);159160nir_ssa_def *point_width, *point_height;161get_scaled_point_size(b, state, &point_width, &point_height);162163nir_instr_remove(&instr->instr);164165for (unsigned i = 0; i < 4; i++) {166/* All outputs need to be emitted for each vertex */167for (unsigned slot = 0; slot < VARYING_SLOT_MAX; ++slot) {168if (state->varying[slot] != NULL) {169nir_store_var(b, state->varying_out[slot], state->varying[slot],170state->varying_write_mask[slot]);171}172}173174/* pos = scaled_point_size * point_dir + point_pos */175nir_ssa_def *point_dir = get_point_dir(b, state, i);176nir_ssa_def *pos = nir_vec4(b,177nir_ffma(b,178point_width,179nir_channel(b, point_dir, 0),180nir_channel(b, state->point_pos, 0)),181nir_ffma(b,182point_height,183nir_channel(b, point_dir, 1),184nir_channel(b, state->point_pos, 1)),185nir_channel(b, state->point_pos, 2),186nir_channel(b, state->point_pos, 3));187nir_store_var(b, state->pos_out, pos, 0xf);188189/* point coord */190nir_ssa_def *point_coord = get_point_coord(b, state, i);191for (unsigned j = 0; j < state->num_point_coords; ++j)192nir_store_var(b, state->point_coord_out[j], point_coord, 0xf);193194/* EmitVertex */195nir_emit_vertex(b, .stream_id = stream_id);196}197198/* EndPrimitive */199nir_end_primitive(b, .stream_id = stream_id);200201/* Reset everything */202state->point_pos = NULL;203state->point_size = NULL;204for (unsigned i = 0; i < VARYING_SLOT_MAX; ++i)205state->varying[i] = NULL;206207return true;208}209210static bool211lower_instr(nir_intrinsic_instr *instr, nir_builder *b, struct lower_state *state)212{213b->cursor = nir_before_instr(&instr->instr);214215if (instr->intrinsic == nir_intrinsic_store_deref) {216return lower_store(instr, b, state);217} else if (instr->intrinsic == nir_intrinsic_emit_vertex) {218return lower_emit_vertex(instr, b, state);219} else if (instr->intrinsic == nir_intrinsic_end_primitive) {220nir_instr_remove(&instr->instr);221return true;222}223224return false;225}226227bool228d3d12_lower_point_sprite(nir_shader *shader,229bool sprite_origin_lower_left,230bool point_size_per_vertex,231unsigned point_coord_enable,232uint64_t next_inputs_read)233{234const gl_state_index16 tokens[4] = { STATE_INTERNAL_DRIVER,235D3D12_STATE_VAR_PT_SPRITE };236struct lower_state state;237bool progress = false;238239assert(shader->info.gs.output_primitive == GL_POINTS);240241memset(&state, 0, sizeof(state));242find_outputs(shader, &state);243state.sprite_origin_lower_left = sprite_origin_lower_left;244state.point_size_per_vertex = point_size_per_vertex;245246/* Create uniform to retrieve inverse of viewport size and point size:247* (1/ViewportWidth, 1/ViewportHeight, PointSize, MaxPointSize) */248state.uniform = nir_variable_create(shader,249nir_var_uniform,250glsl_vec4_type(),251"d3d12_ViewportSizeRcp");252state.uniform->num_state_slots = 1;253state.uniform->state_slots = ralloc_array(state.uniform, nir_state_slot, 1);254memcpy(state.uniform->state_slots[0].tokens, tokens,255sizeof(state.uniform->state_slots[0].tokens));256shader->num_uniforms++;257258/* Create new outputs for point tex coordinates */259unsigned count = 0;260for (unsigned int sem = 0; sem < 9; sem++) {261if (point_coord_enable & BITFIELD64_BIT(sem)) {262char tmp[100];263unsigned location = VARYING_SLOT_VAR0 + sem;264265snprintf(tmp, ARRAY_SIZE(tmp), "gl_TexCoord%dMESA", count);266267nir_variable *var = nir_variable_create(shader,268nir_var_shader_out,269glsl_vec4_type(),270tmp);271var->data.location = location;272state.point_coord_out[count++] = var;273}274}275state.num_point_coords = count;276if (point_coord_enable) {277dxil_reassign_driver_locations(shader, nir_var_shader_out,278next_inputs_read);279}280281nir_foreach_function(function, shader) {282if (function->impl) {283nir_builder builder;284nir_builder_init(&builder, function->impl);285nir_foreach_block(block, function->impl) {286nir_foreach_instr_safe(instr, block) {287if (instr->type == nir_instr_type_intrinsic)288progress |= lower_instr(nir_instr_as_intrinsic(instr),289&builder,290&state);291}292}293294nir_metadata_preserve(function->impl, nir_metadata_block_index |295nir_metadata_dominance);296}297}298299shader->info.gs.output_primitive = GL_TRIANGLE_STRIP;300shader->info.gs.vertices_out *= 4;301302return progress;303}304305306