mesa, st/mesa: fix gl_FragCoord with FBOs in Gallium
authorMarek Olšák <maraeo@gmail.com>
Thu, 2 Dec 2010 19:39:59 +0000 (20:39 +0100)
committerMarek Olšák <maraeo@gmail.com>
Fri, 3 Dec 2010 04:56:40 +0000 (05:56 +0100)
gl_FragCoord.y needs to be flipped upside down if a FBO is bound.

This fixes:
- piglit/fbo-fragcoord
- https://bugs.freedesktop.org/show_bug.cgi?id=29420

Here I add a new program state STATE_FB_WPOS_Y_TRANSFORM, which is set based
on whether a FBO is bound. The state contains a pair of transformations.
It can be either (XY=identity, ZW=transformY) if a FBO is bound,
or (XY=transformY, ZW=identity) otherwise, where identity = (1, 0),
transformY = (-1, height-1).

A classic driver (or st/mesa) may, based on some other state, choose whether
to use XY or ZW, thus negate the conditional "if (is a FBO bound) ...".
The reason for this is that a Gallium driver is allowed to only support WPOS
relative to either the lower left or the upper left corner, so we must flip
the Y axis accordingly again. (the "invert" parameter in emit_wpos_inversion)

NOTE: This is a candidate for the 7.9 branch.

Signed-off-by: Marek Olšák <maraeo@gmail.com>
Signed-off-by: Brian Paul <brianp@vmware.com>
src/mesa/program/prog_statevars.c
src/mesa/program/prog_statevars.h
src/mesa/state_tracker/st_mesa_to_tgsi.c

index baac29ff0dd5dc3d6daea105bae86c9ffb9977c1..83bd3727f33cfc8e221bffc1c2ff9a39ec86065a 100644 (file)
@@ -572,6 +572,24 @@ _mesa_fetch_state(struct gl_context *ctx, const gl_state_index state[],
          value[3] = 0.0F;
          return;
 
+      case STATE_FB_WPOS_Y_TRANSFORM:
+         /* A driver may negate this conditional by using ZW swizzle
+          * instead of XY (based on e.g. some other state). */
+         if (ctx->DrawBuffer->Name != 0) {
+            /* Identity (XY) followed by flipping Y upside down (ZW). */
+            value[0] = 1.0F;
+            value[1] = 0.0F;
+            value[2] = -1.0F;
+            value[3] = (GLfloat) (ctx->DrawBuffer->Height - 1);
+         } else {
+            /* Flipping Y upside down (XY) followed by identity (ZW). */
+            value[0] = -1.0F;
+            value[1] = (GLfloat) (ctx->DrawBuffer->Height - 1);
+            value[2] = 1.0F;
+            value[3] = 0.0F;
+         }
+         return;
+
       case STATE_ROT_MATRIX_0:
          {
             const int unit = (int) state[2];
@@ -695,6 +713,7 @@ _mesa_program_state_flags(const gl_state_index state[STATE_LENGTH])
          return _NEW_PIXEL;
 
       case STATE_FB_SIZE:
+      case STATE_FB_WPOS_Y_TRANSFORM:
          return _NEW_BUFFERS;
 
       default:
@@ -900,6 +919,9 @@ append_token(char *dst, gl_state_index k)
    case STATE_FB_SIZE:
       append(dst, "FbSize");
       break;
+   case STATE_FB_WPOS_Y_TRANSFORM:
+      append(dst, "FbWposYTransform");
+      break;
    case STATE_ROT_MATRIX_0:
       append(dst, "rotMatrixRow0");
       break;
index 6e5be53630c1517991c824dedc90c451437b6ae9..009ebde00128b4f8df4cdfe11d03d0def75b7f2a 100644 (file)
@@ -117,6 +117,7 @@ typedef enum gl_state_index_ {
    STATE_PT_BIAS,               /**< Pixel transfer RGBA bias */
    STATE_SHADOW_AMBIENT,        /**< ARB_shadow_ambient fail value; token[2] is texture unit index */
    STATE_FB_SIZE,               /**< (width-1, height-1, 0, 0) */
+   STATE_FB_WPOS_Y_TRANSFORM,   /**< (1, 0, -1, height-1) if a FBO is bound, (-1, height-1, 1, 0) otherwise */
    STATE_ROT_MATRIX_0,          /**< ATI_envmap_bumpmap, rot matrix row 0 */
    STATE_ROT_MATRIX_1,          /**< ATI_envmap_bumpmap, rot matrix row 1 */
    STATE_INTERNAL_DRIVER       /* first available state index for drivers (must be last) */
index c5c239b2c954874c6612cb1a34657ba50f67f84b..f848462310eb83c41089508d899c13d288cf4d10 100644 (file)
@@ -760,10 +760,13 @@ emit_adjusted_wpos( struct st_translate *t,
 
 /**
  * Emit the TGSI instructions for inverting the WPOS y coordinate.
+ * This code is unavoidable because it also depends on whether
+ * a FBO is bound (STATE_FB_WPOS_Y_TRANSFORM).
  */
 static void
-emit_inverted_wpos( struct st_translate *t,
-                    const struct gl_program *program )
+emit_wpos_inversion( struct st_translate *t,
+                     const struct gl_program *program,
+                     boolean invert)
 {
    struct ureg_program *ureg = t->ureg;
 
@@ -771,17 +774,17 @@ emit_inverted_wpos( struct st_translate *t,
     * Need to replace instances of INPUT[WPOS] with temp T
     * where T = INPUT[WPOS] by y is inverted.
     */
-   static const gl_state_index winSizeState[STATE_LENGTH]
-      = { STATE_INTERNAL, STATE_FB_SIZE, 0, 0, 0 };
+   static const gl_state_index wposTransformState[STATE_LENGTH]
+      = { STATE_INTERNAL, STATE_FB_WPOS_Y_TRANSFORM, 0, 0, 0 };
    
    /* XXX: note we are modifying the incoming shader here!  Need to
     * do this before emitting the constant decls below, or this
     * will be missed:
     */
-   unsigned winHeightConst = _mesa_add_state_reference(program->Parameters,
-                                                       winSizeState);
+   unsigned wposTransConst = _mesa_add_state_reference(program->Parameters,
+                                                       wposTransformState);
 
-   struct ureg_src winsize = ureg_DECL_constant( ureg, winHeightConst );
+   struct ureg_src wpostrans = ureg_DECL_constant( ureg, wposTransConst );
    struct ureg_dst wpos_temp;
    struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]];
 
@@ -794,12 +797,23 @@ emit_inverted_wpos( struct st_translate *t,
       ureg_MOV( ureg, wpos_temp, wpos_input );
    }
 
-   /* SUB wpos_temp.y, winsize_const, wpos_input
-    */
-   ureg_SUB( ureg,
-             ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ),
-             winsize,
-             wpos_input);
+   if (invert) {
+      /* MAD wpos_temp.y, wpos_input, wpostrans.xxxx, wpostrans.yyyy
+       */
+      ureg_MAD( ureg,
+                ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ),
+                wpos_input,
+                ureg_scalar(wpostrans, 0),
+                ureg_scalar(wpostrans, 1));
+   } else {
+      /* MAD wpos_temp.y, wpos_input, wpostrans.zzzz, wpostrans.wwww
+       */
+      ureg_MAD( ureg,
+                ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ),
+                wpos_input,
+                ureg_scalar(wpostrans, 2),
+                ureg_scalar(wpostrans, 3));
+   }
 
    /* Use wpos_temp as position input from here on:
     */
@@ -861,8 +875,7 @@ emit_wpos(struct st_context *st,
 
    /* we invert after adjustment so that we avoid the MOV to temporary,
     * and reuse the adjustment ADD instead */
-   if (invert)
-      emit_inverted_wpos(t, program);
+   emit_wpos_inversion(t, program, invert);
 }