r300: collect input/output info directly from NIR

The NIR IO intrinsics already carry the locations and register bases
used for the generated declarations, so fill r300_shader_semantics while
emitting the NIR loads and stores.

This removes the FS input semantic scan and lets the VS output setup use
the same NIR-derived information. Track the total number of used
inputs/outputs as well.

Also stop depending on tgsi_info for the external constants.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41577>
This commit is contained in:
Pavel Ondračka 2025-12-03 12:52:04 +01:00 committed by Marge Bot
parent 3c295e513c
commit cb7449effb
9 changed files with 120 additions and 77 deletions

View file

@ -56,6 +56,7 @@ struct ntr_compile {
nir_function_impl *impl;
struct pipe_screen *screen;
struct ureg_program *ureg;
struct r300_shader_semantics *semantics;
/* Options */
bool lower_fabs;
@ -244,6 +245,59 @@ ntr_tgsi_var_usage_mask(const struct nir_variable *var)
return BITFIELD_RANGE(var->data.location_frac, num_components);
}
static void
ntr_read_input_output(struct ntr_compile *c, gl_varying_slot location, unsigned base)
{
if (base >= c->semantics->num_total)
c->semantics->num_total = base + 1;
switch (location) {
case VARYING_SLOT_POS:
if (c->s->info.stage == MESA_SHADER_VERTEX)
c->semantics->pos = base;
else
c->semantics->wpos = base;
break;
case VARYING_SLOT_PSIZ:
c->semantics->psize = base;
break;
case VARYING_SLOT_COL0:
c->semantics->color[0] = base;
break;
case VARYING_SLOT_COL1:
c->semantics->color[1] = base;
break;
case VARYING_SLOT_BFC0:
c->semantics->bcolor[0] = base;
break;
case VARYING_SLOT_BFC1:
c->semantics->bcolor[1] = base;
break;
case VARYING_SLOT_FOGC:
c->semantics->fog = base;
break;
case VARYING_SLOT_FACE:
assert(c->s->info.stage == MESA_SHADER_FRAGMENT);
c->semantics->face = base;
break;
case VARYING_SLOT_EDGE:
assert(c->s->info.stage == MESA_SHADER_VERTEX);
fprintf(stderr, "r300 VP: cannot handle edgeflag output.\n");
break;
default:
if (location >= VARYING_SLOT_VAR0 && location <= VARYING_SLOT_VAR31) {
unsigned index = location - VARYING_SLOT_VAR0;
if (c->semantics->generic[index] == ATTR_UNUSED)
c->semantics->num_generic++;
c->semantics->generic[index] = base;
} else {
printf("Unhandled varying slot: %u\n", location);
UNREACHABLE("Unhandled varying slot");
}
break;
}
}
static struct ureg_dst
ntr_output_decl(struct ntr_compile *c, nir_intrinsic_instr *instr, uint32_t *frac)
{
@ -274,6 +328,8 @@ ntr_output_decl(struct ntr_compile *c, nir_intrinsic_instr *instr, uint32_t *fra
tgsi_get_gl_varying_semantic(semantics.location, true, &semantic_name, &semantic_index);
ntr_read_input_output(c, semantics.location, base);
uint32_t usage_mask = BITFIELD_RANGE(*frac, instr->num_components);
out = ureg_DECL_output_layout(c->ureg, semantic_name, semantic_index, 0, base,
usage_mask, 0, semantics.num_slots, false);
@ -1002,6 +1058,9 @@ ntr_emit_load_input(struct ntr_compile *c, nir_intrinsic_instr *instr)
struct ureg_src input;
nir_io_semantics semantics = nir_intrinsic_io_semantics(instr);
if (c->s->info.stage == MESA_SHADER_FRAGMENT)
ntr_read_input_output(c, semantics.location, base);
if (c->s->info.stage == MESA_SHADER_VERTEX) {
input = ureg_DECL_vs_input(c->ureg, base);
for (int i = 1; i < semantics.num_slots; i++)
@ -1787,7 +1846,8 @@ ntr_fixup_varying_slots(nir_shader *s, nir_variable_mode mode)
*/
const void *
nir_to_rc(struct nir_shader *s, struct pipe_screen *screen,
struct r300_fragment_program_external_state state)
struct r300_fragment_program_external_state state,
union r300_shader_code rc)
{
struct ntr_compile *c;
const void *tgsi_tokens;
@ -1795,6 +1855,11 @@ nir_to_rc(struct nir_shader *s, struct pipe_screen *screen,
c = rzalloc(NULL, struct ntr_compile);
c->screen = screen;
c->lower_fabs = !is_r500 && s->info.stage == MESA_SHADER_VERTEX;
if (s->info.stage == MESA_SHADER_FRAGMENT) {
c->semantics = &rc.f->inputs;
} else {
c->semantics = &rc.v->outputs;
}
ntr_fixup_varying_slots(s, s->info.stage == MESA_SHADER_FRAGMENT ? nir_var_shader_in : nir_var_shader_out);
@ -1971,7 +2036,6 @@ nir_to_rc(struct nir_shader *s, struct pipe_screen *screen,
ureg_destroy(c->ureg);
ralloc_free(c);
ralloc_free(s);
return tgsi_tokens;
}

View file

@ -9,13 +9,22 @@
#include <stdbool.h>
#include "compiler/nir/nir.h"
#include "pipe/p_defines.h"
#include "r300_fs.h"
#include "r300_shader_semantics.h"
#include "r300_vs.h"
struct nir_shader;
struct pipe_screen;
struct r300_fragment_program_external_state;
union r300_shader_code {
struct r300_fragment_shader_code *f;
struct r300_vertex_shader_code *v;
};
const void *nir_to_rc(struct nir_shader *s, struct pipe_screen *screen,
struct r300_fragment_program_external_state state);
const void *
nir_to_rc(struct nir_shader *s, struct pipe_screen *screen,
struct r300_fragment_program_external_state state,
union r300_shader_code rc);
void
ntr_fixup_varying_slots(struct nir_shader *s, nir_variable_mode mode);

View file

@ -26,52 +26,6 @@
#include "nir.h"
#include "nir/tgsi_to_nir.h"
/* Convert info about FS input semantics to r300_shader_semantics. */
void r300_shader_read_fs_inputs(struct tgsi_shader_info* info,
struct r300_shader_semantics* fs_inputs)
{
int i;
unsigned index;
r300_shader_semantics_reset(fs_inputs);
for (i = 0; i < info->num_inputs; i++) {
index = info->input_semantic_index[i];
switch (info->input_semantic_name[i]) {
case TGSI_SEMANTIC_COLOR:
assert(index < ATTR_COLOR_COUNT);
fs_inputs->color[index] = i;
break;
case TGSI_SEMANTIC_GENERIC:
assert(index < ATTR_GENERIC_COUNT);
fs_inputs->generic[index] = i;
fs_inputs->num_generic++;
break;
case TGSI_SEMANTIC_FOG:
assert(index == 0);
fs_inputs->fog = i;
break;
case TGSI_SEMANTIC_POSITION:
assert(index == 0);
fs_inputs->wpos = i;
break;
case TGSI_SEMANTIC_FACE:
assert(index == 0);
fs_inputs->face = i;
break;
default:
fprintf(stderr, "r300: FP: Unknown input semantic: %i\n",
info->input_semantic_name[i]);
}
}
}
static void find_output_registers(struct r300_fragment_program_compiler * compiler,
struct r300_fragment_shader_code *shader)
{
@ -412,14 +366,16 @@ static void r300_translate_fragment_shader(
struct tgsi_to_rc ttr;
int wpos, face;
unsigned i;
union r300_shader_code code;
code.f = shader;
if (state.type == PIPE_SHADER_IR_NIR) {
nir_shader *clone = nir_shader_clone(NULL, state.ir.nir);
state.tokens = nir_to_rc(clone, (struct pipe_screen *)r300->screen, shader->compare_state);
}
r300_shader_semantics_reset(&shader->inputs);
nir_shader *clone = nir_shader_clone(NULL, state.ir.nir);
state.tokens = nir_to_rc(clone, (struct pipe_screen *)r300->screen, shader->compare_state,
code);
tgsi_scan_shader(state.tokens, &shader->info);
r300_shader_read_fs_inputs(&shader->info, &shader->inputs);
wpos = shader->inputs.wpos;
face = shader->inputs.face;
@ -456,13 +412,11 @@ static void r300_translate_fragment_shader(
/* Translate TGSI to our internal representation */
ttr.compiler = &compiler.Base;
ttr.info = &shader->info;
ttr.shader = clone;
r300_tgsi_to_rc(&ttr, state.tokens);
if (state.type == PIPE_SHADER_IR_NIR) {
FREE((void*)state.tokens);
}
ralloc_free(clone);
FREE((void*)state.tokens);
if (ttr.error) {
shader->error = strdup("Cannot translate a shader from TGSI.");

View file

@ -13,6 +13,8 @@
#include "compiler/radeon_code.h"
#include "r300_shader_semantics.h"
struct r300_context;
struct r300_fragment_shader_code {
struct rX00_fragment_program_code code;
struct tgsi_shader_info info;
@ -56,9 +58,6 @@ struct r300_fragment_shader {
struct r300_fragment_shader_code* first;
};
void r300_shader_read_fs_inputs(struct tgsi_shader_info* info,
struct r300_shader_semantics* fs_inputs);
/* Return TRUE if the shader was switched and should be re-emitted. */
bool r300_pick_fragment_shader(struct r300_context *r300,
struct r300_fragment_shader* fs,

View file

@ -27,6 +27,9 @@ struct r300_shader_semantics {
int wpos;
int num_generic;
/* Total number of used inputs/outputs. */
unsigned num_total;
};
static inline void r300_shader_semantics_reset(
@ -50,6 +53,7 @@ static inline void r300_shader_semantics_reset(
}
info->num_generic = 0;
info->num_total = 0;
}
#endif

View file

@ -221,7 +221,13 @@ void r300_tgsi_to_rc(struct tgsi_to_rc * ttr,
/* Allocate constants placeholders.
*
* Note: What if declared constants are not contiguous? */
for(i = 0; i <= ttr->info->file_max[TGSI_FILE_CONSTANT]; ++i) {
unsigned num_constants = 0;
nir_foreach_variable_with_modes (var, ttr->shader, nir_var_mem_ubo) {
assert(num_constants == 0);
unsigned size = glsl_get_explicit_size(var->interface_type, false);
num_constants = DIV_ROUND_UP(size, 16);
}
for(i = 0; i < num_constants; ++i) {
struct rc_constant constant;
memset(&constant, 0, sizeof(constant));
constant.Type = RC_CONSTANT_EXTERNAL;

View file

@ -7,6 +7,7 @@
#define R300_TGSI_TO_RC_H
#include "util/compiler.h"
#include "nir/nir.h"
struct radeon_compiler;
@ -21,7 +22,7 @@ struct swizzled_imms {
struct tgsi_to_rc {
struct radeon_compiler * compiler;
const struct tgsi_shader_info * info;
struct nir_shader * shader;
int immediate_offset;

View file

@ -90,13 +90,12 @@ static void set_vertex_inputs_outputs(struct r300_vertex_program_compiler * c)
{
struct r300_vertex_shader_code * vs = c->UserData;
struct r300_shader_semantics* outputs = &vs->outputs;
struct tgsi_shader_info* info = &vs->info;
int i, reg = 0;
bool any_bcolor_used = outputs->bcolor[0] != ATTR_UNUSED ||
outputs->bcolor[1] != ATTR_UNUSED;
/* Fill in the input mapping */
for (i = 0; i < info->num_inputs; i++)
for (i = 0; i < vs->s->num_inputs; i++)
c->code->inputs[i] = i;
/* Position. */
@ -167,19 +166,24 @@ void r300_translate_vertex_shader(struct r300_context *r300,
struct r300_vertex_program_compiler compiler;
struct tgsi_to_rc ttr;
unsigned i;
struct r300_vertex_shader_code *vs = shader->shader;
r300_shader_semantics_reset(&vs->outputs);
nir_shader *clone = nir_shader_clone(NULL, shader->state.ir.nir);
union r300_shader_code code;
code.v = vs;
vs->s = nir_shader_clone(NULL, shader->state.ir.nir);
struct r300_fragment_program_external_state external_state = {};
shader->state.tokens = nir_to_rc(clone, (struct pipe_screen *)r300->screen, external_state);
r300_init_vs_outputs(r300, shader);
shader->state.tokens = nir_to_rc(vs->s, (struct pipe_screen *)r300->screen,
external_state, code);
vs->outputs.wpos = vs->outputs.num_total;
/* Nothing to do if the shader does not write gl_Position. */
if (vs->outputs.pos == ATTR_UNUSED) {
vs->dummy = true;
FREE((void*)shader->state.tokens);
return;
goto cleanup;
}
/* Setup the compiler */
@ -208,7 +212,7 @@ void r300_translate_vertex_shader(struct r300_context *r300,
/* Translate TGSI to our internal representation */
ttr.compiler = &compiler.Base;
ttr.info = &vs->info;
ttr.shader = vs->s;
r300_tgsi_to_rc(&ttr, shader->state.tokens);
FREE((void*)shader->state.tokens);
@ -216,14 +220,14 @@ void r300_translate_vertex_shader(struct r300_context *r300,
if (ttr.error) {
vs->error = strdup("Cannot translate shader from TGSI");
vs->dummy = true;
return;
goto cleanup;
}
if (compiler.Base.Program.Constants.Count > 200) {
compiler.Base.remove_unused_constants = true;
}
compiler.RequiredOutputs = ~(~0U << (vs->info.num_outputs + (vs->wpos ? 1 : 0)));
compiler.RequiredOutputs = ~(~0U << (vs->outputs.num_total + (vs->wpos ? 1 : 0)));
compiler.SetHwInputOutput = &set_vertex_inputs_outputs;
/* Insert the WPOS output. */
@ -234,9 +238,8 @@ void r300_translate_vertex_shader(struct r300_context *r300,
r3xx_compile_vertex_program(&compiler);
if (compiler.Base.Error) {
vs->error = strdup(compiler.Base.ErrorMsg);
rc_destroy(&compiler.Base);
vs->dummy = true;
return;
goto cleanup;
}
/* Initialize numbers of constants for each type. */
@ -252,5 +255,7 @@ void r300_translate_vertex_shader(struct r300_context *r300,
vs->immediates_count = vs->code.constants.Count - vs->externals_count;
/* And, finally... */
cleanup:
ralloc_free(vs->s);
rc_destroy(&compiler.Base);
}

View file

@ -20,6 +20,7 @@ struct r300_vertex_shader_code {
/* Parent class */
struct tgsi_shader_info info;
struct nir_shader *s;
struct r300_shader_semantics outputs;
/* Whether the shader was replaced by a dummy one due to a shader