svga: fix FBO / viewport bugs
authorBrian Paul <brianp@vmware.com>
Mon, 14 May 2012 22:33:58 +0000 (16:33 -0600)
committerBrian Paul <brianp@vmware.com>
Tue, 15 May 2012 20:56:54 +0000 (14:56 -0600)
When drawing to a FBO, the viewport wasn't always set correctly.  It
was fine in the usual case of the viewport dims matching the surface
dims but broken otherwise.  In particular, this was happening because
the viewport scale is negative for FBO rendering.

The piglit fbo-viewport test exercises this.

Reviewed-by: José Fonseca <jfonseca@vmware.com>
src/gallium/drivers/svga/svga_state_framebuffer.c

index 3244023f3ad3b56a5727be44b6ef1ad8fdc2e062..402d5feac999da857227860b3118634b5d6d17be 100644 (file)
@@ -175,6 +175,7 @@ emit_viewport( struct svga_context *svga,
    float range_max = 1.0;
    float flip = -1.0;
    boolean degenerate = FALSE;
+   boolean invertY = FALSE;
    enum pipe_error ret;
 
    float fb_width = svga->curr.framebuffer.width;
@@ -218,11 +219,12 @@ emit_viewport( struct svga_context *svga,
       fx =        viewport->scale[0] * 1.0 + viewport->translate[0];
    }
 
-   if (fh < 0) {
-      prescale.scale[1] *= -1.0;
-      prescale.translate[1] += -fh;
+   if (fh < 0.0) {
+      prescale.translate[1] = fh - 1 + fy * 2;
       fh = -fh;
-      fy = flip * viewport->scale[1] * 1.0 + viewport->translate[1];
+      fy -= fh;
+      prescale.scale[1] = -1.0;
+      invertY = TRUE;
    }
 
    if (fx < 0) {
@@ -233,7 +235,12 @@ emit_viewport( struct svga_context *svga,
    }
 
    if (fy < 0) {
-      prescale.translate[1] += fy;
+      if (invertY) {
+         prescale.translate[1] -= fy;
+      }
+      else {
+         prescale.translate[1] += fy;
+      }
       prescale.scale[1] *= fh / (fh + fy); 
       fh += fy;
       fy = 0;
@@ -249,8 +256,15 @@ emit_viewport( struct svga_context *svga,
 
    if (fy + fh > fb_height) {
       prescale.scale[1] *= fh / (fb_height - fy);
-      prescale.translate[1] -= fy * (fh / (fb_height - fy));
-      prescale.translate[1] += fy;
+      if (invertY) {
+         float in = fb_height - fy;       /* number of vp pixels inside view */
+         float out = fy + fh - fb_height; /* number of vp pixels out of view */
+         prescale.translate[1] += fy * out / in;
+      }
+      else {
+         prescale.translate[1] -= fy * (fh / (fb_height - fy));
+         prescale.translate[1] += fy;
+      }
       fh = fb_height - fy;
    }
 
@@ -307,6 +321,9 @@ emit_viewport( struct svga_context *svga,
          break;
       }
 
+      if (invertY)
+         adjust_y = -adjust_y;
+
       prescale.translate[0] += adjust_x;
       prescale.translate[1] += adjust_y;
       prescale.translate[2] = 0.5; /* D3D clip space */