mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-07 02:48:06 +02:00
etnaviv: Add per-RT frag_rb_swap shader key and NIR lowering
Add a per-RT bitmask to the shader key that triggers R/B channel
swapping in the fragment shader output. Handles scalar through vec4
outputs by widening to vec4 first, then swapping channels 0 and 2
with adjusted writemask.
Preparation for LINEAR_PE GPUs where shared linear resources have no
render shadow, so the shader must produce correct byte order directly.
No functional change - nothing sets frag_rb_swap yet.
Fixes: a5766e75e48 ("etnaviv: Use BGRA-internal texture format with BLT/RS R/B swizzle")
Signed-off-by: Christian Gmeiner <cgmeiner@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40029>
This commit is contained in:
parent
cfa8deaad9
commit
99bf43dd08
2 changed files with 93 additions and 0 deletions
|
|
@ -26,6 +26,18 @@
|
|||
|
||||
#include "etnaviv_nir.h"
|
||||
|
||||
static inline int
|
||||
color_index_for_location(unsigned location)
|
||||
{
|
||||
assert(location != FRAG_RESULT_COLOR &&
|
||||
"gl_FragColor must be lowered before nir_lower_blend");
|
||||
|
||||
if (location < FRAG_RESULT_DATA0)
|
||||
return -1;
|
||||
else
|
||||
return location - FRAG_RESULT_DATA0;
|
||||
}
|
||||
|
||||
/* io related lowering
|
||||
* run after lower_int_to_float because it adds i2f/f2i ops
|
||||
*/
|
||||
|
|
@ -34,6 +46,35 @@ etna_lower_io(nir_shader *shader, struct etna_shader_variant *v)
|
|||
{
|
||||
bool progress = false;
|
||||
|
||||
/* Phase 1: Widen fragment color output variables to vec4 for R/B swap.
|
||||
*
|
||||
* The R/B channel swap needs to reorder components and adjust the
|
||||
* writemask. NIR store_deref validation requires num_components ==
|
||||
* glsl_get_vector_elements(deref->type) and writemask bits must be
|
||||
* within BITFIELD_MASK(num_components). So for scalar/vec2/vec3
|
||||
* outputs we must widen the variable type to vec4 first.
|
||||
*/
|
||||
if (shader->info.stage == MESA_SHADER_FRAGMENT && v->key.frag_rb_swap) {
|
||||
nir_foreach_shader_out_variable(var, shader) {
|
||||
int rt = color_index_for_location(var->data.location);
|
||||
if (rt == -1 || !(v->key.frag_rb_swap & (1 << rt)))
|
||||
continue;
|
||||
|
||||
const glsl_type *type = var->type;
|
||||
if (glsl_type_is_array(type)) {
|
||||
const glsl_type *elem = glsl_get_array_element(type);
|
||||
if (glsl_get_vector_elements(elem) < 4) {
|
||||
var->type = glsl_array_type(
|
||||
glsl_vector_type(glsl_get_base_type(elem), 4),
|
||||
glsl_array_size(type), 0);
|
||||
}
|
||||
} else {
|
||||
if (glsl_get_vector_elements(type) < 4)
|
||||
var->type = glsl_vector_type(glsl_get_base_type(type), 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nir_foreach_function_impl(impl, shader) {
|
||||
nir_builder b = nir_builder_create(impl);
|
||||
bool func_progress = false;
|
||||
|
|
@ -60,6 +101,56 @@ etna_lower_io(nir_shader *shader, struct etna_shader_variant *v)
|
|||
|
||||
func_progress = true;
|
||||
} break;
|
||||
case nir_intrinsic_store_deref: {
|
||||
nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
|
||||
if (shader->info.stage != MESA_SHADER_FRAGMENT ||
|
||||
!v->key.frag_rb_swap)
|
||||
break;
|
||||
|
||||
nir_variable *var = nir_deref_instr_get_variable(deref);
|
||||
int rt = color_index_for_location(var->data.location);
|
||||
if (rt == -1)
|
||||
break;
|
||||
|
||||
if (!(v->key.frag_rb_swap & (1 << rt)))
|
||||
break;
|
||||
|
||||
/* Phase 2: Update deref type to match widened variable and
|
||||
* perform R/B channel swap via pad + swizzle + writemask.
|
||||
*/
|
||||
if (deref->deref_type == nir_deref_type_var) {
|
||||
deref->type = var->type;
|
||||
} else {
|
||||
/* Array deref: update parent deref_var and this element */
|
||||
nir_deref_instr *parent = nir_deref_instr_parent(deref);
|
||||
assert(parent->deref_type == nir_deref_type_var);
|
||||
parent->type = var->type;
|
||||
deref->type = glsl_get_array_element(var->type);
|
||||
}
|
||||
|
||||
b.cursor = nir_before_instr(instr);
|
||||
|
||||
nir_def *src = intr->src[1].ssa;
|
||||
unsigned old_wrmask = nir_intrinsic_write_mask(intr);
|
||||
|
||||
/* Pad source to 4 components (undef for missing) */
|
||||
nir_def *padded = nir_pad_vec4(&b, src);
|
||||
|
||||
/* Swap R and B channels */
|
||||
unsigned swiz[] = {2, 1, 0, 3};
|
||||
nir_def *swapped = nir_swizzle(&b, padded, swiz, 4);
|
||||
|
||||
/* Swap bits 0 and 2 in writemask */
|
||||
unsigned new_wrmask = (old_wrmask & ~5u) |
|
||||
((old_wrmask & 1u) << 2) |
|
||||
((old_wrmask & 4u) >> 2);
|
||||
|
||||
intr->num_components = 4;
|
||||
nir_intrinsic_set_write_mask(intr, new_wrmask);
|
||||
nir_src_rewrite(&intr->src[1], swapped);
|
||||
|
||||
func_progress = true;
|
||||
} break;
|
||||
case nir_intrinsic_load_vertex_id:
|
||||
case nir_intrinsic_load_instance_id:
|
||||
/* detect use of vertex_id/instance_id */
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ struct etna_shader_key
|
|||
* Combined Vertex/Fragment shader parameters:
|
||||
*/
|
||||
|
||||
/* per-RT bitmask: swap R/B in frag shader for shared resources */
|
||||
unsigned frag_rb_swap : 8;
|
||||
/* do we need to invert front facing value? */
|
||||
unsigned front_ccw : 1;
|
||||
/* do we need to replace glTexCoord.xy ? */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue