zink: add gl_point lowering pass

This lowering pass is intended for hardwares/drivers that can't honor
the gl_PointSize when GL_PROGRAM_POINT_SIZE is enabled.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20109>
This commit is contained in:
Igor Torrente 2022-12-01 09:41:48 -03:00 committed by Marge Bot
parent da5840f385
commit ea5b2b9c4c

View file

@ -273,6 +273,114 @@ lower_drawid(nir_shader *shader)
return nir_shader_instructions_pass(shader, lower_drawid_instr, nir_metadata_dominance, NULL);
}
struct lower_gl_point_state {
nir_variable *gl_pos_out;
nir_variable *gl_point_size;
};
static bool
lower_gl_point_gs_instr(nir_builder *b, nir_instr *instr, void *data)
{
struct lower_gl_point_state *state = data;
nir_ssa_def *vp_scale, *pos;
if (instr->type != nir_instr_type_intrinsic)
return false;
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
if (intrin->intrinsic != nir_intrinsic_emit_vertex_with_counter &&
intrin->intrinsic != nir_intrinsic_emit_vertex)
return false;
if (nir_intrinsic_stream_id(intrin) != 0)
return false;
if (intrin->intrinsic == nir_intrinsic_end_primitive_with_counter ||
intrin->intrinsic == nir_intrinsic_end_primitive) {
nir_instr_remove(&intrin->instr);
return true;
}
b->cursor = nir_before_instr(instr);
// viewport-map endpoints
nir_ssa_def *vp_const_pos = nir_imm_int(b, ZINK_GFX_PUSHCONST_VIEWPORT_SCALE);
vp_scale = nir_load_push_constant(b, 2, 32, vp_const_pos, .base = 1, .range = 2);
// Load point info values
nir_ssa_def *point_size = nir_load_var(b, state->gl_point_size);
nir_ssa_def *point_pos = nir_load_var(b, state->gl_pos_out);
// w_delta = gl_point_size / width_viewport_size_scale * gl_Position.w
nir_ssa_def *w_delta = nir_fdiv(b, point_size, nir_channel(b, vp_scale, 0));
w_delta = nir_fmul(b, w_delta, nir_channel(b, point_pos, 3));
// halt_w_delta = w_delta / 2
nir_ssa_def *half_w_delta = nir_fmul(b, w_delta, nir_imm_float(b, 0.5));
// h_delta = gl_point_size / height_viewport_size_scale * gl_Position.w
nir_ssa_def *h_delta = nir_fdiv(b, point_size, nir_channel(b, vp_scale, 1));
h_delta = nir_fmul(b, h_delta, nir_channel(b, point_pos, 3));
// halt_h_delta = h_delta / 2
nir_ssa_def *half_h_delta = nir_fmul(b, h_delta, nir_imm_float(b, 0.5));
nir_ssa_def *point_dir[4][2] = {
{ nir_imm_float(b, -1), nir_imm_float(b, -1) },
{ nir_imm_float(b, -1), nir_imm_float(b, 1) },
{ nir_imm_float(b, 1), nir_imm_float(b, -1) },
{ nir_imm_float(b, 1), nir_imm_float(b, 1) }
};
nir_ssa_def *point_pos_x = nir_channel(b, point_pos, 0);
nir_ssa_def *point_pos_y = nir_channel(b, point_pos, 1);
for (size_t i = 0; i < 4; i++) {
pos = nir_vec4(b,
nir_ffma(b, half_w_delta, point_dir[i][0], point_pos_x),
nir_ffma(b, half_h_delta, point_dir[i][1], point_pos_y),
nir_channel(b, point_pos, 2),
nir_channel(b, point_pos, 3));
nir_store_var(b, state->gl_pos_out, pos, 0xf);
nir_emit_vertex(b);
}
nir_end_primitive(b);
nir_instr_remove(&intrin->instr);
return true;
}
static bool
lower_gl_point_gs(nir_shader *shader)
{
struct lower_gl_point_state state;
nir_builder b;
shader->info.gs.output_primitive = SHADER_PRIM_TRIANGLE_STRIP;
shader->info.gs.vertices_out *= 4;
// Gets the gl_Position in and out
state.gl_pos_out =
nir_find_variable_with_location(shader, nir_var_shader_out,
VARYING_SLOT_POS);
state.gl_point_size =
nir_find_variable_with_location(shader, nir_var_shader_out,
VARYING_SLOT_PSIZ);
// if position in or gl_PointSize aren't written, we have nothing to do
if (!state.gl_pos_out || !state.gl_point_size)
return false;
nir_function_impl *entry = nir_shader_get_entrypoint(shader);
nir_builder_init(&b, entry);
b.cursor = nir_before_cf_list(&entry->body);
return nir_shader_instructions_pass(shader, lower_gl_point_gs_instr,
nir_metadata_dominance, &state);
}
struct lower_line_stipple_state {
nir_variable *pos_out;
nir_variable *stipple_out;