radv: add a NIR pass that lower fragment shader barycentric intrinsics
Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16742>
This commit is contained in:

committed by
Marge Bot

parent
2b156c8258
commit
7ee8a12a62
@@ -75,6 +75,7 @@ libradv_files = files(
|
|||||||
'nir/radv_nir_apply_pipeline_layout.c',
|
'nir/radv_nir_apply_pipeline_layout.c',
|
||||||
'nir/radv_nir_export_multiview.c',
|
'nir/radv_nir_export_multiview.c',
|
||||||
'nir/radv_nir_lower_abi.c',
|
'nir/radv_nir_lower_abi.c',
|
||||||
|
'nir/radv_nir_lower_fs_barycentric.c',
|
||||||
'nir/radv_nir_lower_fs_intrinsics.c',
|
'nir/radv_nir_lower_fs_intrinsics.c',
|
||||||
'nir/radv_nir_lower_intrinsics_early.c',
|
'nir/radv_nir_lower_intrinsics_early.c',
|
||||||
'nir/radv_nir_lower_io.c',
|
'nir/radv_nir_lower_io.c',
|
||||||
|
@@ -62,6 +62,9 @@ bool radv_nir_lower_primitive_shading_rate(nir_shader *nir, enum amd_gfx_level g
|
|||||||
bool radv_nir_lower_fs_intrinsics(nir_shader *nir, const struct radv_pipeline_stage *fs_stage,
|
bool radv_nir_lower_fs_intrinsics(nir_shader *nir, const struct radv_pipeline_stage *fs_stage,
|
||||||
const struct radv_pipeline_key *key);
|
const struct radv_pipeline_key *key);
|
||||||
|
|
||||||
|
bool radv_nir_lower_fs_barycentric(nir_shader *shader, const struct radv_pipeline_key *key,
|
||||||
|
unsigned rast_prim);
|
||||||
|
|
||||||
bool radv_nir_lower_intrinsics_early(nir_shader *nir, const struct radv_pipeline_key *key);
|
bool radv_nir_lower_intrinsics_early(nir_shader *nir, const struct radv_pipeline_key *key);
|
||||||
|
|
||||||
bool radv_nir_lower_view_index(nir_shader *nir, bool per_primitive);
|
bool radv_nir_lower_view_index(nir_shader *nir, bool per_primitive);
|
||||||
|
308
src/amd/vulkan/nir/radv_nir_lower_fs_barycentric.c
Normal file
308
src/amd/vulkan/nir/radv_nir_lower_fs_barycentric.c
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2023 Valve Corporation
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nir/nir.h"
|
||||||
|
#include "nir/nir_builder.h"
|
||||||
|
#include "radv_nir.h"
|
||||||
|
#include "radv_private.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool dynamic_rasterization_samples;
|
||||||
|
unsigned num_rasterization_samples;
|
||||||
|
unsigned rast_prim;
|
||||||
|
} lower_fs_barycentric_state;
|
||||||
|
|
||||||
|
static nir_ssa_def *
|
||||||
|
lower_interp_center_smooth(nir_builder *b, nir_ssa_def *offset)
|
||||||
|
{
|
||||||
|
nir_ssa_def *pull_model = nir_load_barycentric_model(b, 32);
|
||||||
|
|
||||||
|
nir_ssa_def *deriv_x = nir_vec3(b, nir_fddx_fine(b, nir_channel(b, pull_model, 0)),
|
||||||
|
nir_fddx_fine(b, nir_channel(b, pull_model, 1)),
|
||||||
|
nir_fddx_fine(b, nir_channel(b, pull_model, 2)));
|
||||||
|
nir_ssa_def *deriv_y = nir_vec3(b, nir_fddy_fine(b, nir_channel(b, pull_model, 0)),
|
||||||
|
nir_fddy_fine(b, nir_channel(b, pull_model, 1)),
|
||||||
|
nir_fddy_fine(b, nir_channel(b, pull_model, 2)));
|
||||||
|
|
||||||
|
nir_ssa_def *offset_x = nir_channel(b, offset, 0);
|
||||||
|
nir_ssa_def *offset_y = nir_channel(b, offset, 1);
|
||||||
|
|
||||||
|
nir_ssa_def *adjusted_x = nir_fadd(b, pull_model, nir_fmul(b, deriv_x, offset_x));
|
||||||
|
nir_ssa_def *adjusted = nir_fadd(b, adjusted_x, nir_fmul(b, deriv_y, offset_y));
|
||||||
|
|
||||||
|
nir_ssa_def *ij = nir_vec2(b, nir_channel(b, adjusted, 0), nir_channel(b, adjusted, 1));
|
||||||
|
|
||||||
|
/* Get W by using the reciprocal of 1/W. */
|
||||||
|
nir_ssa_def *w = nir_frcp(b, nir_channel(b, adjusted, 2));
|
||||||
|
|
||||||
|
return nir_fmul(b, ij, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static nir_ssa_def *
|
||||||
|
lower_barycentric_coord_at_offset(nir_builder *b, nir_ssa_def *src, enum glsl_interp_mode mode)
|
||||||
|
{
|
||||||
|
if (mode == INTERP_MODE_SMOOTH)
|
||||||
|
return lower_interp_center_smooth(b, src);
|
||||||
|
|
||||||
|
return nir_load_barycentric_at_offset(b, 32, src, .interp_mode = mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static nir_ssa_def *
|
||||||
|
lower_barycentric_coord_at_sample(nir_builder *b, lower_fs_barycentric_state *state,
|
||||||
|
nir_intrinsic_instr *intrin)
|
||||||
|
{
|
||||||
|
const enum glsl_interp_mode mode = (enum glsl_interp_mode)nir_intrinsic_interp_mode(intrin);
|
||||||
|
nir_ssa_def *num_samples = nir_load_rasterization_samples_amd(b);
|
||||||
|
nir_ssa_def *new_dest;
|
||||||
|
|
||||||
|
if (state->dynamic_rasterization_samples) {
|
||||||
|
nir_ssa_def *res1, *res2;
|
||||||
|
|
||||||
|
nir_push_if(b, nir_ieq_imm(b, num_samples, 1));
|
||||||
|
{
|
||||||
|
res1 = nir_load_barycentric_pixel(
|
||||||
|
b, 32, .interp_mode = nir_intrinsic_interp_mode(intrin));
|
||||||
|
}
|
||||||
|
nir_push_else(b, NULL);
|
||||||
|
{
|
||||||
|
nir_ssa_def *sample_pos =
|
||||||
|
nir_load_sample_positions_amd(b, 32, intrin->src[0].ssa, num_samples);
|
||||||
|
|
||||||
|
/* sample_pos -= 0.5 */
|
||||||
|
sample_pos = nir_fadd_imm(b, sample_pos, -0.5f);
|
||||||
|
|
||||||
|
res2 = lower_barycentric_coord_at_offset(b, sample_pos, mode);
|
||||||
|
}
|
||||||
|
nir_pop_if(b, NULL);
|
||||||
|
|
||||||
|
new_dest = nir_if_phi(b, res1, res2);
|
||||||
|
} else {
|
||||||
|
if (!state->num_rasterization_samples) {
|
||||||
|
new_dest = nir_load_barycentric_pixel(
|
||||||
|
b, 32, .interp_mode = nir_intrinsic_interp_mode(intrin));
|
||||||
|
} else {
|
||||||
|
nir_ssa_def *sample_pos =
|
||||||
|
nir_load_sample_positions_amd(b, 32, intrin->src[0].ssa, num_samples);
|
||||||
|
|
||||||
|
/* sample_pos -= 0.5 */
|
||||||
|
sample_pos = nir_fadd_imm(b, sample_pos, -0.5f);
|
||||||
|
|
||||||
|
new_dest = lower_barycentric_coord_at_offset(b, sample_pos, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static nir_ssa_def *
|
||||||
|
get_interp_param(nir_builder *b, lower_fs_barycentric_state *state, nir_intrinsic_instr *intrin)
|
||||||
|
{
|
||||||
|
const enum glsl_interp_mode mode = (enum glsl_interp_mode)nir_intrinsic_interp_mode(intrin);
|
||||||
|
|
||||||
|
if (intrin->intrinsic == nir_intrinsic_load_barycentric_coord_pixel) {
|
||||||
|
return nir_load_barycentric_pixel(b, 32, .interp_mode = mode);
|
||||||
|
} else if (intrin->intrinsic == nir_intrinsic_load_barycentric_coord_at_offset) {
|
||||||
|
return lower_barycentric_coord_at_offset(b, intrin->src[0].ssa, mode);
|
||||||
|
} else if (intrin->intrinsic == nir_intrinsic_load_barycentric_coord_at_sample) {
|
||||||
|
return lower_barycentric_coord_at_sample(b, state, intrin);
|
||||||
|
} else if (intrin->intrinsic == nir_intrinsic_load_barycentric_coord_centroid) {
|
||||||
|
return nir_load_barycentric_centroid(b, 32, .interp_mode = mode);
|
||||||
|
} else {
|
||||||
|
assert(intrin->intrinsic == nir_intrinsic_load_barycentric_coord_sample);
|
||||||
|
return nir_load_barycentric_sample(b, 32, .interp_mode = mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static nir_ssa_def *
|
||||||
|
lower_point(nir_builder *b)
|
||||||
|
{
|
||||||
|
nir_ssa_def *coords[3];
|
||||||
|
|
||||||
|
coords[0] = nir_imm_float(b, 1.0f);
|
||||||
|
coords[1] = nir_imm_float(b, 0.0f);
|
||||||
|
coords[2] = nir_imm_float(b, 0.0f);
|
||||||
|
|
||||||
|
return nir_vec(b, coords, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static nir_ssa_def *
|
||||||
|
lower_line(nir_builder *b, nir_ssa_def *p1, nir_ssa_def *p2)
|
||||||
|
{
|
||||||
|
nir_ssa_def *coords[3];
|
||||||
|
|
||||||
|
coords[1] = nir_fadd(b, p1, p2);
|
||||||
|
coords[0] = nir_fsub(b, nir_imm_float(b, 1.0f), coords[1]);
|
||||||
|
coords[2] = nir_imm_float(b, 0.0f);
|
||||||
|
|
||||||
|
return nir_vec(b, coords, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static nir_ssa_def *
|
||||||
|
lower_triangle(nir_builder *b, nir_ssa_def *p1, nir_ssa_def *p2)
|
||||||
|
{
|
||||||
|
nir_ssa_def *v0_bary[3], *v1_bary[3], *v2_bary[3];
|
||||||
|
nir_ssa_def *coords[3];
|
||||||
|
|
||||||
|
/* Compute the provoking vertex ID:
|
||||||
|
*
|
||||||
|
* quad_id = thread_id >> 2
|
||||||
|
* provoking_vtx_id = (provoking_vtx >> (quad_id << 1)) & 3
|
||||||
|
*/
|
||||||
|
nir_ssa_def *quad_id = nir_ushr_imm(b, nir_load_subgroup_invocation(b), 2);
|
||||||
|
nir_ssa_def *provoking_vtx = nir_load_provoking_vtx_amd(b);
|
||||||
|
nir_ssa_def *provoking_vtx_id =
|
||||||
|
nir_ubfe(b, provoking_vtx, nir_ishl_imm(b, quad_id, 1), nir_imm_int(b, 2));
|
||||||
|
|
||||||
|
/* Compute barycentrics. */
|
||||||
|
v0_bary[0] = nir_fsub(b, nir_fsub(b, nir_imm_float(b, 1.0f), p2), p1);
|
||||||
|
v0_bary[1] = p1;
|
||||||
|
v0_bary[2] = p2;
|
||||||
|
|
||||||
|
v1_bary[0] = p1;
|
||||||
|
v1_bary[1] = p2;
|
||||||
|
v1_bary[2] = nir_fsub(b, nir_fsub(b, nir_imm_float(b, 1.0f), p2), p1);
|
||||||
|
|
||||||
|
v2_bary[0] = p2;
|
||||||
|
v2_bary[1] = nir_fsub(b, nir_fsub(b, nir_imm_float(b, 1.0f), p2), p1);
|
||||||
|
v2_bary[2] = p1;
|
||||||
|
|
||||||
|
/* Select barycentrics for the given provoking vertex ID. */
|
||||||
|
for (unsigned i = 0; i < 3; i++) {
|
||||||
|
coords[i] = nir_bcsel(b, nir_ieq_imm(b, provoking_vtx_id, 2), v2_bary[i],
|
||||||
|
nir_bcsel(b, nir_ieq_imm(b, provoking_vtx_id, 1), v1_bary[i], v0_bary[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return nir_vec(b, coords, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
lower_load_barycentric_coord(nir_builder *b, lower_fs_barycentric_state *state,
|
||||||
|
nir_intrinsic_instr *intrin)
|
||||||
|
{
|
||||||
|
nir_ssa_def *interp, *p1, *p2;
|
||||||
|
nir_ssa_def *new_dest;
|
||||||
|
|
||||||
|
b->cursor = nir_after_instr(&intrin->instr);
|
||||||
|
|
||||||
|
/* When the rasterization primitive isn't known at compile time (GPL), load it. */
|
||||||
|
if (state->rast_prim == -1) {
|
||||||
|
nir_ssa_def *rast_prim = nir_load_rasterization_primitive_amd(b);
|
||||||
|
nir_ssa_def *res1, *res2;
|
||||||
|
|
||||||
|
nir_ssa_def *is_point = nir_ieq_imm(b, rast_prim, V_028A6C_POINTLIST);
|
||||||
|
nir_if *if_point = nir_push_if(b, is_point);
|
||||||
|
{
|
||||||
|
res1 = lower_point(b);
|
||||||
|
}
|
||||||
|
nir_push_else(b, if_point);
|
||||||
|
{
|
||||||
|
nir_ssa_def *res_line, *res_triangle;
|
||||||
|
|
||||||
|
interp = get_interp_param(b, state, intrin);
|
||||||
|
p1 = nir_channel(b, interp, 0);
|
||||||
|
p2 = nir_channel(b, interp, 1);
|
||||||
|
|
||||||
|
nir_ssa_def *is_line = nir_ieq_imm(b, rast_prim, V_028A6C_LINESTRIP);
|
||||||
|
nir_if *if_line = nir_push_if(b, is_line);
|
||||||
|
{
|
||||||
|
res_line = lower_line(b, p1, p2);
|
||||||
|
}
|
||||||
|
nir_push_else(b, if_line);
|
||||||
|
{
|
||||||
|
res_triangle = lower_triangle(b, p1, p2);
|
||||||
|
}
|
||||||
|
nir_pop_if(b, if_line);
|
||||||
|
|
||||||
|
res2 = nir_if_phi(b, res_line, res_triangle);
|
||||||
|
}
|
||||||
|
nir_pop_if(b, if_point);
|
||||||
|
|
||||||
|
new_dest = nir_if_phi(b, res1, res2);
|
||||||
|
} else {
|
||||||
|
if (state->rast_prim == V_028A6C_POINTLIST) {
|
||||||
|
new_dest = lower_point(b);
|
||||||
|
} else {
|
||||||
|
interp = get_interp_param(b, state, intrin);
|
||||||
|
p1 = nir_channel(b, interp, 0);
|
||||||
|
p2 = nir_channel(b, interp, 1);
|
||||||
|
|
||||||
|
if (state->rast_prim == V_028A6C_LINESTRIP) {
|
||||||
|
new_dest = lower_line(b, p1, p2);
|
||||||
|
} else {
|
||||||
|
assert(state->rast_prim == V_028A6C_TRISTRIP);
|
||||||
|
new_dest = lower_triangle(b, p1, p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nir_ssa_def_rewrite_uses(&intrin->dest.ssa, new_dest);
|
||||||
|
nir_instr_remove(&intrin->instr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
radv_nir_lower_fs_barycentric(nir_shader *shader, const struct radv_pipeline_key *key,
|
||||||
|
unsigned rast_prim)
|
||||||
|
{
|
||||||
|
nir_function_impl *impl = nir_shader_get_entrypoint(shader);
|
||||||
|
bool progress = false;
|
||||||
|
|
||||||
|
nir_builder b;
|
||||||
|
|
||||||
|
lower_fs_barycentric_state state = {
|
||||||
|
.dynamic_rasterization_samples = key->dynamic_rasterization_samples,
|
||||||
|
.num_rasterization_samples = key->ps.num_samples,
|
||||||
|
.rast_prim = rast_prim,
|
||||||
|
};
|
||||||
|
|
||||||
|
nir_foreach_function (function, shader) {
|
||||||
|
if (!function->impl)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nir_builder_init(&b, function->impl);
|
||||||
|
|
||||||
|
nir_foreach_block (block, impl) {
|
||||||
|
nir_foreach_instr_safe (instr, block) {
|
||||||
|
if (instr->type != nir_instr_type_intrinsic)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
|
||||||
|
if (intrin->intrinsic != nir_intrinsic_load_barycentric_coord_pixel &&
|
||||||
|
intrin->intrinsic != nir_intrinsic_load_barycentric_coord_centroid &&
|
||||||
|
intrin->intrinsic != nir_intrinsic_load_barycentric_coord_sample &&
|
||||||
|
intrin->intrinsic != nir_intrinsic_load_barycentric_coord_at_offset &&
|
||||||
|
intrin->intrinsic != nir_intrinsic_load_barycentric_coord_at_sample)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
progress |= lower_load_barycentric_coord(&b, &state, intrin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nir_metadata_preserve(impl, progress ? nir_metadata_none : nir_metadata_all);
|
||||||
|
|
||||||
|
return progress;
|
||||||
|
}
|
@@ -2571,6 +2571,34 @@ radv_pipeline_create_ps_epilog(struct radv_device *device, struct radv_graphics_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
radv_get_rasterization_prim(const struct radv_pipeline_stage *stages,
|
||||||
|
const struct radv_pipeline_key *pipeline_key)
|
||||||
|
{
|
||||||
|
unsigned rast_prim;
|
||||||
|
|
||||||
|
if (pipeline_key->unknown_rast_prim)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (stages[MESA_SHADER_GEOMETRY].nir) {
|
||||||
|
rast_prim =
|
||||||
|
si_conv_gl_prim_to_gs_out(stages[MESA_SHADER_GEOMETRY].nir->info.gs.output_primitive);
|
||||||
|
} else if (stages[MESA_SHADER_TESS_EVAL].nir) {
|
||||||
|
if (stages[MESA_SHADER_TESS_EVAL].nir->info.tess.point_mode) {
|
||||||
|
rast_prim = V_028A6C_POINTLIST;
|
||||||
|
} else {
|
||||||
|
rast_prim =
|
||||||
|
si_conv_tess_prim_to_gs_out(stages[MESA_SHADER_TESS_EVAL].nir->info.tess._primitive_mode);
|
||||||
|
}
|
||||||
|
} else if (stages[MESA_SHADER_MESH].nir) {
|
||||||
|
rast_prim = si_conv_gl_prim_to_gs_out(stages[MESA_SHADER_MESH].nir->info.mesh.primitive_type);
|
||||||
|
} else {
|
||||||
|
rast_prim = si_conv_prim_to_gs_out(pipeline_key->vs.topology, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rast_prim;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
radv_skip_graphics_pipeline_compile(const struct radv_device *device,
|
radv_skip_graphics_pipeline_compile(const struct radv_device *device,
|
||||||
const struct radv_graphics_pipeline *pipeline,
|
const struct radv_graphics_pipeline *pipeline,
|
||||||
@@ -2761,6 +2789,13 @@ radv_graphics_pipeline_compile(struct radv_graphics_pipeline *pipeline,
|
|||||||
|
|
||||||
radv_graphics_pipeline_link(device, pipeline, pipeline_key, stages);
|
radv_graphics_pipeline_link(device, pipeline, pipeline_key, stages);
|
||||||
|
|
||||||
|
if (stages[MESA_SHADER_FRAGMENT].nir) {
|
||||||
|
unsigned rast_prim = radv_get_rasterization_prim(stages, pipeline_key);
|
||||||
|
|
||||||
|
NIR_PASS(_, stages[MESA_SHADER_FRAGMENT].nir, radv_nir_lower_fs_barycentric, pipeline_key,
|
||||||
|
rast_prim);
|
||||||
|
}
|
||||||
|
|
||||||
radv_foreach_stage (i, active_nir_stages) {
|
radv_foreach_stage (i, active_nir_stages) {
|
||||||
int64_t stage_start = os_time_get_nano();
|
int64_t stage_start = os_time_get_nano();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user