gallium/draw: support lowering stipple + smooth

When computing line smoothing, we can also do something similar to
compute the line stippling. This can be useful for some drivers, who
can't easily split the lines before rasterizing them.

This does lead to slightly inaccurate stippling, because the
line-smoothing extends the line-length by a small amount. That leads to
the line-stippling pattern being over-stretched over the line-segment by
a fraction of a pixel in lenght. For short lines, this can be quite a
lot of error.

Reviewed-by: Soroush Kashani <soroush.kashani@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20134>
This commit is contained in:
Erik Faye-Lund 2022-12-02 13:33:48 +01:00 committed by Marge Bot
parent 180e30857c
commit c69637a2a5
4 changed files with 50 additions and 6 deletions

View file

@ -361,7 +361,7 @@ generate_aaline_fs_nir(struct aaline_stage *aaline)
if (!aaline_fs.ir.nir) if (!aaline_fs.ir.nir)
return FALSE; return FALSE;
nir_lower_aaline_fs(aaline_fs.ir.nir, &aaline->fs->generic_attrib); nir_lower_aaline_fs(aaline_fs.ir.nir, &aaline->fs->generic_attrib, NULL, NULL);
aaline->fs->aaline_fs = aaline->driver_create_fs_state(pipe, &aaline_fs); aaline->fs->aaline_fs = aaline->driver_create_fs_state(pipe, &aaline_fs);
if (aaline->fs->aaline_fs == NULL) if (aaline->fs->aaline_fs == NULL)
return FALSE; return FALSE;

View file

@ -148,6 +148,8 @@ nir_lower_pstipple_fs(struct nir_shader *shader,
typedef struct { typedef struct {
nir_variable *line_width_input; nir_variable *line_width_input;
nir_variable *stipple_counter;
nir_variable *stipple_pattern;
} lower_aaline; } lower_aaline;
static bool static bool
@ -176,8 +178,43 @@ lower_aaline_instr(nir_builder *b, nir_instr *instr, void *data)
nir_ssa_def *tmp = nir_fsat(b, nir_fadd(b, nir_channels(b, lw, 0xa), nir_ssa_def *tmp = nir_fsat(b, nir_fadd(b, nir_channels(b, lw, 0xa),
nir_fneg(b, nir_fabs(b, nir_channels(b, lw, 0x5))))); nir_fneg(b, nir_fabs(b, nir_channels(b, lw, 0x5)))));
nir_ssa_def *max = len;
if (state->stipple_counter) {
assert(state->stipple_pattern);
nir_ssa_def *counter = nir_load_var(b, state->stipple_counter);
nir_ssa_def *pattern = nir_load_var(b, state->stipple_pattern);
nir_ssa_def *factor = nir_i2f32(b, nir_ishr_imm(b, pattern, 16));
pattern = nir_iand_imm(b, pattern, 0xffff);
nir_ssa_def *stipple_pos = nir_vec2(b, nir_fadd_imm(b, counter, -0.5),
nir_fadd_imm(b, counter, 0.5));
stipple_pos = nir_frem(b, nir_fdiv(b, stipple_pos, factor),
nir_imm_float(b, 16.0));
nir_ssa_def *p = nir_f2i32(b, stipple_pos);
nir_ssa_def *one = nir_imm_float(b, 1.0);
// float t = 1.0 - min((1.0 - fract(stipple_pos.x)) * factor, 1.0);
nir_ssa_def *t = nir_ffract(b, nir_channel(b, stipple_pos, 0));
t = nir_fsub(b, one,
nir_fmin(b, nir_fmul(b, factor,
nir_fsub(b, one, t)), one));
// vec2 a = vec2((uvec2(pattern) >> p) & uvec2(1u));
nir_ssa_def *a = nir_i2f32(b,
nir_iand(b, nir_ishr(b, nir_vec2(b, pattern, pattern), p),
nir_imm_ivec2(b, 1, 1)));
// float cov = mix(a.x, a.y, t);
nir_ssa_def *cov = nir_flrp(b, nir_channel(b, a, 0), nir_channel(b, a, 1), t);
max = nir_fmin(b, len, cov);
}
tmp = nir_fmul(b, nir_channel(b, tmp, 0), tmp = nir_fmul(b, nir_channel(b, tmp, 0),
nir_fmin(b, nir_channel(b, tmp, 1), len)); nir_fmin(b, nir_channel(b, tmp, 1), max));
tmp = nir_fmul(b, nir_channel(b, out_input, 3), tmp); tmp = nir_fmul(b, nir_channel(b, out_input, 3), tmp);
nir_ssa_def *out = nir_vec4(b, nir_channel(b, out_input, 0), nir_ssa_def *out = nir_vec4(b, nir_channel(b, out_input, 0),
@ -189,9 +226,14 @@ lower_aaline_instr(nir_builder *b, nir_instr *instr, void *data)
} }
void void
nir_lower_aaline_fs(struct nir_shader *shader, int *varying) nir_lower_aaline_fs(struct nir_shader *shader, int *varying,
nir_variable *stipple_counter,
nir_variable *stipple_pattern)
{ {
lower_aaline state; lower_aaline state = {
.stipple_counter = stipple_counter,
.stipple_pattern = stipple_pattern,
};
assert(shader->info.stage == MESA_SHADER_FRAGMENT); assert(shader->info.stage == MESA_SHADER_FRAGMENT);
int highest_location = -1, highest_drv_location = -1; int highest_location = -1, highest_drv_location = -1;

View file

@ -38,7 +38,9 @@ nir_lower_pstipple_fs(struct nir_shader *shader,
bool fs_pos_is_sysval); bool fs_pos_is_sysval);
void void
nir_lower_aaline_fs(struct nir_shader *shader, int *varying); nir_lower_aaline_fs(struct nir_shader *shader, int *varying,
nir_variable *stipple_counter,
nir_variable *stipple_pattern);
void void
nir_lower_aapoint_fs(struct nir_shader *shader, int *varying); nir_lower_aapoint_fs(struct nir_shader *shader, int *varying);

View file

@ -813,7 +813,7 @@ static bool
lower_line_smooth_fs(nir_shader *shader) lower_line_smooth_fs(nir_shader *shader)
{ {
int dummy; int dummy;
nir_lower_aaline_fs(shader, &dummy); nir_lower_aaline_fs(shader, &dummy, NULL, NULL);
return true; return true;
} }