r300: always convert to NIR and move ntr later

Always convert TGSI shaders to NIR up-front in r300_create_{fs,vs}_state
so the rest of the compile pipeline only ever has to deal with NIR. The
TGSI->RC translation in r300_translate_{fragment,vertex}_shader now
always goes through nir_to_rc.

This requires shifting r300_blitter_draw_rectangle's sprite_coord_enable
bit from 0 to 9. The blitter's GENERIC[0] FS input now lands at
fs_inputs->generic[9] after the +9 shift in ntr_fixup_varying_slots, so
the rasterizer's sprite_coord_enable check needs the matching bit.

The draw path still needs TGSI, so we convert it back explicitly for
now. The deTGSIzation of draw paths will come later.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41577>
This commit is contained in:
Pavel Ondračka 2025-12-03 12:51:38 +01:00 committed by Marge Bot
parent 2546882763
commit 3c295e513c
6 changed files with 72 additions and 18 deletions

View file

@ -1760,7 +1760,7 @@ nir_to_rc_lower_txp(nir_shader *s)
* like vs using generics and fs using texcoords. This function tries to fix it.
* See https://gitlab.freedesktop.org/mesa/mesa/-/issues/12749 for more details.
*/
static void
void
ntr_fixup_varying_slots(nir_shader *s, nir_variable_mode mode)
{
if (s->info.name && !strcmp(s->info.name, "st/drawtex VS"))

View file

@ -7,6 +7,7 @@
#define NIR_TO_RC_H
#include <stdbool.h>
#include "compiler/nir/nir.h"
#include "pipe/p_defines.h"
struct nir_shader;
@ -16,4 +17,7 @@ struct r300_fragment_program_external_state;
const void *nir_to_rc(struct nir_shader *s, struct pipe_screen *screen,
struct r300_fragment_program_external_state state);
void
ntr_fixup_varying_slots(struct nir_shader *s, nir_variable_mode mode);
#endif /* NIR_TO_RC_H */

View file

@ -24,6 +24,7 @@
#include "compiler/radeon_compiler.h"
#include "compiler/nir_to_rc.h"
#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,
@ -198,7 +199,7 @@ static void r300_dummy_fragment_shader(
struct r300_context* r300,
struct r300_fragment_shader_code* shader)
{
struct pipe_shader_state state;
struct pipe_shader_state state = {};
struct ureg_program *ureg;
struct ureg_dst out;
struct ureg_src imm;
@ -214,7 +215,11 @@ static void r300_dummy_fragment_shader(
state.tokens = ureg_finalize(ureg);
shader->dummy = true;
state.type = PIPE_SHADER_IR_NIR;
/* We could just build a NIR directly, was lazy to figure it out for now... */
state.ir.nir = tgsi_to_nir(state.tokens, &r300->screen->screen, false);
r300_translate_fragment_shader(r300, shader, state);
ralloc_free(state.ir.nir);
ureg_destroy(ureg);
}

View file

@ -1248,7 +1248,16 @@ void r300_blitter_draw_rectangle(struct blitter_context *blitter,
r300->context.bind_vs_state(&r300->context, get_vs(blitter));
if (type == UTIL_BLITTER_ATTRIB_TEXCOORD_XY) {
r300->sprite_coord_enable = 1;
/* The blitter's passthrough VS outputs GENERIC[0], which u_blitter
* encodes here as sprite_coord_enable bit 0. After
* ntr_fixup_varying_slots in nir_to_rc, the corresponding FS input
* lands at index 9 in fs_inputs->generic[] (VAR0 -> VAR9 from the
* +9 shift that leaves room for TEX0..TEX7 and PNTC). Match that
* by setting bit 9 instead of bit 0; the rest of the rasterizer
* setup (r300_state_derived.c) walks generic[i] and tests
* sprite_coord_enable & (1 << i) so the indices need to agree.
*/
r300->sprite_coord_enable = 1 << 9;
r300->is_point = true;
}

View file

@ -15,6 +15,9 @@
#include "util/u_transfer.h"
#include "util/u_blend.h"
#include "nir/nir_to_tgsi.h"
#include "nir/tgsi_to_nir.h"
#include "tgsi/tgsi_parse.h"
#include "util/detect.h"
@ -1232,8 +1235,9 @@ static void* r300_create_fs_state(struct pipe_context* pipe,
}
} else {
assert(fs->state.type == PIPE_SHADER_IR_TGSI);
/* we need to keep a local copy of the tokens */
fs->state.tokens = tgsi_dup_tokens(fs->state.tokens);
/* Convert to NIR. */
fs->state.ir.nir = tgsi_to_nir(fs->state.tokens, pipe->screen, false);
fs->state.type = PIPE_SHADER_IR_NIR;
}
/* Precompile the fragment shader at creation time to avoid jank at runtime.
@ -1244,7 +1248,7 @@ static void* r300_create_fs_state(struct pipe_context* pipe,
if (fs->state.type == PIPE_SHADER_IR_NIR) {
/* Pick something for the shadow samplers so that we have somewhat reliable shader stats later. */
nir_foreach_function_impl(impl, shader->ir.nir) {
nir_foreach_function_impl(impl, fs->state.ir.nir) {
nir_foreach_block_safe(block, impl) {
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_tex)
@ -2165,27 +2169,47 @@ static void* r300_create_vs_state(struct pipe_context* pipe,
/* Copy state directly into shader. */
vs->state = *shader;
if (vs->state.type == PIPE_SHADER_IR_NIR) {
r300_optimize_nir(shader->ir.nir, r300->screen);
/* Always convert TGSI input to NIR up front */
if (vs->state.type == PIPE_SHADER_IR_TGSI) {
vs->state.ir.nir = tgsi_to_nir(vs->state.tokens, pipe->screen, false);
vs->state.type = PIPE_SHADER_IR_NIR;
}
/* Run the same NIR optimization/lowering for both HW and SW TCL.
* The LLVM-based draw emulation likely doesn't need the full
* hardware-targeted set of passes (e.g. the scalar/vector
* vectorization-or-scalarization choices, or much of the algebraic
* lowering); we could trim this for the draw path later to just
* what nir_to_rc actually requires - notably scalarizing vector
* comparisons (otherwise nir_lower_bool_to_float asserts) and
* keeping VS outputs aligned with FS inputs via the +9 varying-slot
* shift.
*/
r300_optimize_nir(vs->state.ir.nir, r300->screen);
if (r300->screen->caps.has_tcl) {
/* R300/R400 can not do any kind of control flow, so abort early here. */
if (!r300->screen->caps.is_r500 && r300->screen->caps.has_tcl) {
char *msg = r300_check_control_flow(shader->ir.nir);
if (!r300->screen->caps.is_r500) {
char *msg = r300_check_control_flow(vs->state.ir.nir);
if (msg && shader->report_compile_error) {
fprintf(stderr, "r300 VP: Compiler error: %s\n", msg);
((struct pipe_shader_state *)shader)->error_message = strdup(msg);
ralloc_free(shader->ir.nir);
ralloc_free(vs->state.ir.nir);
FREE(vs);
return NULL;
}
}
struct r300_fragment_program_external_state state = {};
vs->state.tokens = nir_to_rc(shader->ir.nir, pipe->screen, state);
} else {
assert(vs->state.type == PIPE_SHADER_IR_TGSI);
/* we need to keep a local copy of the tokens */
vs->state.tokens = tgsi_dup_tokens(vs->state.tokens);
/* r300_draw_init_vertex_shader needs TGSI tokens.
* Apply the +9 varying shift to keep VS outputs aligned with the
* FS inputs (which always go through nir_to_rc and pick up the
* same shift), then go through the stock gallium nir_to_tgsi.
*/
nir_shader *clone = nir_shader_clone(NULL, vs->state.ir.nir);
ralloc_free(vs->state.ir.nir);
ntr_fixup_varying_slots(clone, nir_var_shader_out);
vs->state.tokens = nir_to_tgsi(clone, pipe->screen);
vs->state.type = PIPE_SHADER_IR_TGSI;
}
if (!vs->first)
@ -2277,7 +2301,11 @@ static void r300_delete_vs_state(struct pipe_context* pipe, void* shader)
(struct draw_vertex_shader*)vs->draw_vs);
}
FREE((void*)vs->state.tokens);
if (vs->state.type == PIPE_SHADER_IR_NIR) {
ralloc_free(vs->state.ir.nir);
} else {
FREE((void*)vs->state.tokens);
}
FREE(shader);
}

View file

@ -13,7 +13,9 @@
#include "tgsi/tgsi_dump.h"
#include "compiler/nir_to_rc.h"
#include "compiler/radeon_compiler.h"
#include "nir/nir.h"
/* Convert info about VS output semantics into r300_shader_semantics. */
static void r300_shader_read_vs_outputs(
@ -167,11 +169,16 @@ void r300_translate_vertex_shader(struct r300_context *r300,
unsigned i;
struct r300_vertex_shader_code *vs = shader->shader;
nir_shader *clone = 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);
/* 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;
}
@ -204,6 +211,7 @@ void r300_translate_vertex_shader(struct r300_context *r300,
ttr.info = &vs->info;
r300_tgsi_to_rc(&ttr, shader->state.tokens);
FREE((void*)shader->state.tokens);
if (ttr.error) {
vs->error = strdup("Cannot translate shader from TGSI");