mesa/ARB_fp: Use the NIR pass for adding fog code instead of ARB instrs.
authorEmma Anholt <emma@anholt.net>
Tue, 16 May 2023 21:36:20 +0000 (14:36 -0700)
committerMarge Bot <emma+marge@anholt.net>
Thu, 1 Jun 2023 23:57:32 +0000 (23:57 +0000)
Tested with
https://gitlab.freedesktop.org/mesa/piglit/-/merge_requests/813

Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23111>

src/mesa/main/shader_types.h
src/mesa/program/arbprogparse.c
src/mesa/program/prog_to_nir.c
src/mesa/program/programopt.c
src/mesa/program/programopt.h
src/mesa/state_tracker/st_nir_lower_fog.c

index 3117a1d..0f90504 100644 (file)
@@ -685,6 +685,9 @@ struct gl_program
           * programs.
           */
          GLboolean IsPositionInvariant;
+
+         /** Used by ARB_fp programs, enum gl_fog_mode */
+         unsigned Fog;
       } arb;
    };
 };
index ba87abb..26c3ec6 100644 (file)
@@ -120,6 +120,7 @@ _mesa_parse_arb_fragment_program(struct gl_context* ctx, GLenum target,
    program->info.fs.pixel_center_integer = state.option.PixelCenterInteger;
 
    program->info.fs.uses_discard = state.fragment.UsesKill;
+   program->arb.Fog = state.option.Fog;
 
    ralloc_free(program->arb.Instructions);
    program->arb.Instructions = prog.arb.Instructions;
@@ -128,18 +129,6 @@ _mesa_parse_arb_fragment_program(struct gl_context* ctx, GLenum target,
       _mesa_free_parameter_list(program->Parameters);
    program->Parameters    = prog.Parameters;
 
-   /* Append fog instructions now if the program has "OPTION ARB_fog_exp"
-    * or similar.  We used to leave this up to drivers, but it appears
-    * there's no hardware that wants to do fog in a discrete stage separate
-    * from the fragment shader.
-    */
-   if (state.option.Fog != FOG_NONE) {
-      /* XXX: we should somehow recompile this to remove clamping if disabled
-       * On the ATI driver, this is unclampled if fragment clamping is disabled
-       */
-      _mesa_append_fog_code(ctx, program, state.option.Fog, GL_TRUE);
-   }
-
 #if DEBUG_FP
    printf("____________Fragment program %u ________\n", program->Id);
    _mesa_print_program(&program->Base);
index 5479639..14d9995 100644 (file)
@@ -36,6 +36,7 @@
 #include "prog_parameter.h"
 #include "prog_print.h"
 #include "program.h"
+#include "state_tracker/st_nir.h"
 
 /**
  * \file prog_to_nir.c
@@ -1031,6 +1032,10 @@ prog_to_nir(const struct gl_context *ctx, const struct gl_program *prog,
    s->info.io_lowered = false;
    s->info.internal = false;
 
+   /* Add OPTION ARB_fog_exp code */
+   if (prog->arb.Fog)
+      NIR_PASS_V(s, st_nir_lower_fog, prog->arb.Fog, prog->Parameters);
+
 fail:
    if (c->error) {
       ralloc_free(s);
index 5930414..ba390d5 100644 (file)
@@ -221,193 +221,3 @@ _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_program *vprog)
    else
       insert_mvp_mad_code( ctx, vprog );
 }
-      
-
-
-
-
-
-/**
- * Append instructions to implement fog
- *
- * The \c fragment.fogcoord input is used to compute the fog blend factor.
- *
- * \param ctx      The GL context
- * \param fprog    Fragment program that fog instructions will be appended to.
- * \param fog_mode Fog mode.  One of \c FOG_EXP, \c FOG_EXP2, or \c FOG_LINEAR.
- * \param saturate True if writes to color outputs should be clamped to [0, 1]
- *
- * \note
- * This function sets \c VARYING_BIT_FOGC in \c fprog->info.inputs_read.
- *
- * \todo With a little work, this function could be adapted to add fog code
- * to vertex programs too.
- */
-void
-_mesa_append_fog_code(struct gl_context *ctx, struct gl_program *fprog,
-                      enum gl_fog_mode fog_mode, GLboolean saturate)
-{
-   static const gl_state_index16 fogPStateOpt[STATE_LENGTH]
-      = { STATE_FOG_PARAMS_OPTIMIZED, 0, 0 };
-   static const gl_state_index16 fogColorState[STATE_LENGTH]
-      = { STATE_FOG_COLOR, 0, 0, 0 };
-   struct prog_instruction *newInst, *inst;
-   const GLuint origLen = fprog->arb.NumInstructions;
-   const GLuint newLen = origLen + 5;
-   GLuint i;
-   GLint fogPRefOpt, fogColorRef; /* state references */
-   GLuint colorTemp, fogFactorTemp; /* temporary registerss */
-
-   if (fog_mode == FOG_NONE) {
-      _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program"
-                    " with fog_mode == GL_NONE");
-      return;
-   }
-
-   if (!(fprog->info.outputs_written & (1 << FRAG_RESULT_COLOR))) {
-      /* program doesn't output color, so nothing to do */
-      return;
-   }
-
-   /* Alloc storage for new instructions */
-   newInst = rzalloc_array(fprog, struct prog_instruction, newLen);
-   if (!newInst) {
-      _mesa_error(ctx, GL_OUT_OF_MEMORY,
-                  "glProgramString(inserting fog_option code)");
-      return;
-   }
-
-   /* Copy orig instructions into new instruction buffer */
-   _mesa_copy_instructions(newInst, fprog->arb.Instructions, origLen);
-
-   /* PARAM fogParamsRefOpt = internal optimized fog params; */
-   fogPRefOpt
-      = _mesa_add_state_reference(fprog->Parameters, fogPStateOpt);
-   /* PARAM fogColorRef = state.fog.color; */
-   fogColorRef
-      = _mesa_add_state_reference(fprog->Parameters, fogColorState);
-
-   /* TEMP colorTemp; */
-   colorTemp = fprog->arb.NumTemporaries++;
-   /* TEMP fogFactorTemp; */
-   fogFactorTemp = fprog->arb.NumTemporaries++;
-
-   /* Scan program to find where result.color is written */
-   inst = newInst;
-   for (i = 0; i < fprog->arb.NumInstructions; i++) {
-      if (inst->Opcode == OPCODE_END)
-         break;
-      if (inst->DstReg.File == PROGRAM_OUTPUT &&
-          inst->DstReg.Index == FRAG_RESULT_COLOR) {
-         /* change the instruction to write to colorTemp w/ clamping */
-         inst->DstReg.File = PROGRAM_TEMPORARY;
-         inst->DstReg.Index = colorTemp;
-         inst->Saturate = saturate;
-         /* don't break (may be several writes to result.color) */
-      }
-      inst++;
-   }
-   assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */
-
-   _mesa_init_instructions(inst, 5);
-
-   /* emit instructions to compute fog blending factor */
-   /* this is always clamped to [0, 1] regardless of fragment clamping */
-   if (fog_mode == FOG_LINEAR) {
-      /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */
-      inst->Opcode = OPCODE_MAD;
-      inst->DstReg.File = PROGRAM_TEMPORARY;
-      inst->DstReg.Index = fogFactorTemp;
-      inst->DstReg.WriteMask = WRITEMASK_X;
-      inst->SrcReg[0].File = PROGRAM_INPUT;
-      inst->SrcReg[0].Index = VARYING_SLOT_FOGC;
-      inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
-      inst->SrcReg[1].File = PROGRAM_STATE_VAR;
-      inst->SrcReg[1].Index = fogPRefOpt;
-      inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
-      inst->SrcReg[2].File = PROGRAM_STATE_VAR;
-      inst->SrcReg[2].Index = fogPRefOpt;
-      inst->SrcReg[2].Swizzle = SWIZZLE_YYYY;
-      inst->Saturate = GL_TRUE;
-      inst++;
-   }
-   else {
-      assert(fog_mode == FOG_EXP || fog_mode == FOG_EXP2);
-      /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */
-      /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */
-      /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */
-      inst->Opcode = OPCODE_MUL;
-      inst->DstReg.File = PROGRAM_TEMPORARY;
-      inst->DstReg.Index = fogFactorTemp;
-      inst->DstReg.WriteMask = WRITEMASK_X;
-      inst->SrcReg[0].File = PROGRAM_STATE_VAR;
-      inst->SrcReg[0].Index = fogPRefOpt;
-      inst->SrcReg[0].Swizzle
-         = (fog_mode == FOG_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW;
-      inst->SrcReg[1].File = PROGRAM_INPUT;
-      inst->SrcReg[1].Index = VARYING_SLOT_FOGC;
-      inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
-      inst++;
-      if (fog_mode == FOG_EXP2) {
-         /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */
-         inst->Opcode = OPCODE_MUL;
-         inst->DstReg.File = PROGRAM_TEMPORARY;
-         inst->DstReg.Index = fogFactorTemp;
-         inst->DstReg.WriteMask = WRITEMASK_X;
-         inst->SrcReg[0].File = PROGRAM_TEMPORARY;
-         inst->SrcReg[0].Index = fogFactorTemp;
-         inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
-         inst->SrcReg[1].File = PROGRAM_TEMPORARY;
-         inst->SrcReg[1].Index = fogFactorTemp;
-         inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
-         inst++;
-      }
-      /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */
-      inst->Opcode = OPCODE_EX2;
-      inst->DstReg.File = PROGRAM_TEMPORARY;
-      inst->DstReg.Index = fogFactorTemp;
-      inst->DstReg.WriteMask = WRITEMASK_X;
-      inst->SrcReg[0].File = PROGRAM_TEMPORARY;
-      inst->SrcReg[0].Index = fogFactorTemp;
-      inst->SrcReg[0].Negate = NEGATE_XYZW;
-      inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
-      inst->Saturate = GL_TRUE;
-      inst++;
-   }
-   /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */
-   inst->Opcode = OPCODE_LRP;
-   inst->DstReg.File = PROGRAM_OUTPUT;
-   inst->DstReg.Index = FRAG_RESULT_COLOR;
-   inst->DstReg.WriteMask = WRITEMASK_XYZ;
-   inst->SrcReg[0].File = PROGRAM_TEMPORARY;
-   inst->SrcReg[0].Index = fogFactorTemp;
-   inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
-   inst->SrcReg[1].File = PROGRAM_TEMPORARY;
-   inst->SrcReg[1].Index = colorTemp;
-   inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
-   inst->SrcReg[2].File = PROGRAM_STATE_VAR;
-   inst->SrcReg[2].Index = fogColorRef;
-   inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
-   inst++;
-   /* MOV result.color.w, colorTemp.x;  # copy alpha */
-   inst->Opcode = OPCODE_MOV;
-   inst->DstReg.File = PROGRAM_OUTPUT;
-   inst->DstReg.Index = FRAG_RESULT_COLOR;
-   inst->DstReg.WriteMask = WRITEMASK_W;
-   inst->SrcReg[0].File = PROGRAM_TEMPORARY;
-   inst->SrcReg[0].Index = colorTemp;
-   inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
-   inst++;
-   /* END; */
-   inst->Opcode = OPCODE_END;
-   inst++;
-
-   /* free old instructions */
-   ralloc_free(fprog->arb.Instructions);
-
-   /* install new instructions */
-   fprog->arb.Instructions = newInst;
-   fprog->arb.NumInstructions = inst - newInst;
-   fprog->info.inputs_read |= VARYING_BIT_FOGC;
-   assert(fprog->info.outputs_written & (1 << FRAG_RESULT_COLOR));
-}
index bf4e42c..cfd08a5 100644 (file)
@@ -40,10 +40,6 @@ struct gl_program;
 extern void
 _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_program *vprog);
 
-extern void
-_mesa_append_fog_code(struct gl_context *ctx, struct gl_program *fprog,
-                      enum gl_fog_mode fog_mode, GLboolean saturate);
-
 #ifdef __cplusplus
 }
 #endif
index 2815b65..918f828 100644 (file)
@@ -89,7 +89,7 @@ st_nir_lower_fog_instr(nir_builder *b, nir_instr *instr, void *_state)
       return false;
 
    int loc = nir_intrinsic_io_semantics(intr).location;
-   if (loc != FRAG_RESULT_COLOR)
+   if (loc != FRAG_RESULT_COLOR && loc != FRAG_RESULT_DATA0)
       return false;
 
    b->cursor = nir_before_instr(instr);
@@ -121,11 +121,23 @@ st_nir_lower_fog(nir_shader *s, enum gl_fog_mode fog_mode, struct gl_program_par
                                    &state);
    } else {
       nir_variable *color_var = nir_find_variable_with_location(s, nir_var_shader_out, FRAG_RESULT_COLOR);
+      if (!color_var) {
+         color_var = nir_find_variable_with_location(s, nir_var_shader_out, FRAG_RESULT_DATA0);
+         /* Fog result would be undefined if we had no output color (in ARB_fragment_program) */
+         if (!color_var)
+            return false;
+      }
 
       nir_builder b;
       nir_builder_init(&b, nir_shader_get_entrypoint(s));
       b.cursor = nir_after_block(nir_impl_last_block(b.impl));
 
+      /* Note: while ARB_fragment_program plus ARB_draw_buffers allows an array
+       * of result colors, prog_to_nir generates separate vars per slot so we
+       * don't have to handle that.  Fog only applies to the first color result.
+       */
+      assert(!glsl_type_is_array(color_var->type));
+
       nir_ssa_def *color = nir_load_var(&b, color_var);
       color = fog_result(&b, color, fog_mode, paramList);
       nir_store_var(&b, color_var, color, 0x7);