Index: radeon_video.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_video.c,v
retrieving revision 1.27
diff -u -r1.27 radeon_video.c
--- radeon_video.c	11 Sep 2005 20:58:53 -0000	1.27
+++ radeon_video.c	27 Nov 2006 19:35:17 -0000
@@ -2100,6 +2101,61 @@
     }
 }
 
+static void
+RADEONCopyDataPlanar(ScrnInfoPtr pScrn,
+                     unsigned char *src1,
+                     unsigned char *src2,
+                     unsigned char *src3,
+                     unsigned char *dst1,
+                     unsigned char *dst2,
+                     unsigned char *dst3,
+                     int srcPitch,
+                     int srcPitch2,
+                     int dstPitch,
+                     int h,
+                     int w)
+{
+    RADEONInfoPtr info = RADEONPTR(pScrn);
+    int count;
+
+    count = h;
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "src1 %x src2 %x src3 %x dst1 %x dst2 %x dst3 %x\n",
+		src1, src2, src3, dst1, dst2, dst3);
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "srcPitch %d srcPitch2 %d dstPitch %d h %d w %d\n",
+		srcPitch, srcPitch2, dstPitch, h, w);
+
+
+    while (count--) {
+        memcpy(dst1, src1, w);
+        src1 += srcPitch;
+        dst1 += dstPitch;
+    }
+
+    w >>= 1;
+    h >>= 1;
+    dstPitch >>= 1;
+
+    count = h;
+
+    while (count--) {
+        memcpy(dst2, src2, w);
+        src2 += srcPitch2;
+        dst2 += dstPitch;
+    }
+
+    count = h;
+
+    while (count--) {
+        memcpy(dst3, src3, w);
+        src3 += srcPitch2;
+        dst3 += dstPitch;
+    }
+
+	FLUSH_RING();
+}
+
+#if 0
 static void RADEON_420_422(
     unsigned int *d,
     unsigned char *s1,
@@ -2114,6 +2170,7 @@
 	n--;
     }
 }
+#endif
 
 
 static void
@@ -2190,6 +2247,7 @@
     }
 }
 
+#if 0
 static void
 RADEONCopyMungedData(
    ScrnInfoPtr pScrn,
@@ -2285,6 +2343,7 @@
 #endif
     }
 }
+#endif
 
 /* Allocates memory, either by resizing the allocation pointed to by mem_struct,
  * or by freeing mem_struct (if non-NULL) and allocating a new space.  The size
@@ -2400,6 +2459,7 @@
     int id,
     int offset1, int offset2,
     int offset3, int offset4,
+    int offset5, int offset6,
     short width, short height,
     int pitch,
     int left, int right, int top,
@@ -2413,7 +2473,8 @@
     int v_inc, h_inc, h_inc_uv, step_by_y, step_by_uv, tmp;
     double h_inc_d;
     int p1_h_accum_init, p23_h_accum_init;
-    int p1_v_accum_init;
+    int p1_v_accum_init, p23_v_accum_init;
+    int p23_blank_lines;
     int ecp_div;
     int v_inc_shift;
     int y_mult;
@@ -2427,9 +2488,14 @@
     CARD32 scale_cntl;
     double dsr;
     int tap_set;
+    int is_planar;
 
-    is_rgb=0;
+    is_rgb=0; is_planar=0;
     switch(id){
+        case FOURCC_I420:
+        case FOURCC_YV12:
+            is_planar=1;
+            break;
         case FOURCC_RGBA32:
         case FOURCC_RGB24:
         case FOURCC_RGBT16:
@@ -2510,7 +2576,6 @@
 	i=i/2;
     	}
 
-
     h_inc_d = src_w;
     h_inc_d = h_inc_d/drw_w;
     /* we could do a tad better  - but why
@@ -2524,7 +2589,8 @@
         step_by_y++;
         step_by_uv = step_by_y;
         h_inc >>= 1;
-        }
+    }
+
     h_inc_uv = h_inc>>(step_by_uv-step_by_y);
     h_inc = h_inc * h_inc_d;
     h_inc_uv = h_inc_uv * h_inc_d;
@@ -2542,10 +2608,26 @@
 
     /* keep everything in 16.16 */
 
-    offset1 += ((left >> 16) & ~7) << 1;
-    offset2 += ((left >> 16) & ~7) << 1;
-    offset3 += ((left >> 16) & ~7) << 1;
-    offset4 += ((left >> 16) & ~7) << 1;
+    if (is_planar) {
+        offset1 += (left & ~15);
+	offset2 += ((left >> 1) & ~15);
+	offset3 += ((left >> 1) & ~15);
+	offset4 += (left & ~15);
+	offset5 += ((left >> 1) & ~15);
+	offset6 += ((left >> 1) & ~15);
+	offset2 |= RADEON_VIF_BUF0_PITCH_SEL;
+	offset3 |= RADEON_VIF_BUF0_PITCH_SEL;
+	offset5 |= RADEON_VIF_BUF0_PITCH_SEL;
+	offset6 |= RADEON_VIF_BUF0_PITCH_SEL;
+    }
+    else {
+	offset1 += (left & ~7) << 1;
+	offset2 += (left & ~7) << 1;
+	offset3 += (left & ~7) << 1;
+	offset4 += (left & ~7) << 1;
+	offset5 += (left & ~7) << 1;
+	offset6 += (left & ~7) << 1;
+    }
 
     if (info->IsSecondary) {
 	offset1 += info->FbMapSize;
@@ -2566,6 +2648,16 @@
     p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 
     	(((deinterlacing_method!=METHOD_WEAVE)&&!is_rgb)?0x03:0x01);
 
+    if (is_planar) {
+	p23_v_accum_init = ((tmp << 4) & 0x03ff8000) |
+	    ((deinterlacing_method != METHOD_WEAVE) ? 0x03 : 0x01);
+	p23_blank_lines = ((((src_h + 1) >> 1)- 1) << 16);
+    }
+    else {
+	p23_v_accum_init = 0;
+	p23_blank_lines = 0;
+    }
+
     left = (left >> 16) & 7;
 
     RADEONWaitForFifo(pScrn, 2);
@@ -2573,18 +2665,7 @@
     if (info->accelOn) RADEON_SYNC(info, pScrn);
     while(!(INREG(RADEON_OV0_REG_LOAD_CNTL) & (1 << 3)));
 
-    dsr=(double)(1<<0xC)/h_inc;
-    if(dsr<0.25)dsr=0.25;
-    if(dsr>1.0)dsr=1.0;
-    tap_set=(int)((dsr-0.25)*100);
-    for(i=0;i<5;i++){
-	    OUTREG(RADEON_OV0_FOUR_TAP_COEF_0+i*4, (TapCoeffs[tap_set].coeff[i][0] &0xf) | 
-	    	((TapCoeffs[tap_set].coeff[i][1] &0x7f)<<8) | 
-	    	((TapCoeffs[tap_set].coeff[i][2] &0x7f)<<16) | 
-	    	((TapCoeffs[tap_set].coeff[i][3] &0xf)<<24));
-		}
-
-    RADEONWaitForFifo(pScrn, 14);
+    RADEONWaitForFifo(pScrn, 10);
     OUTREG(RADEON_OV0_H_INC, h_inc | ((h_inc_uv >> 1) << 16));
     OUTREG(RADEON_OV0_STEP_BY, step_by_y | (step_by_uv << 8));
 
@@ -2644,25 +2725,27 @@
 	    	((TapCoeffs[tap_set].coeff[i][3] &0xf)<<24));
 		}
 
-    RADEONWaitForFifo(pScrn, 10);
+    RADEONWaitForFifo(pScrn, 12);
     OUTREG(RADEON_OV0_V_INC, v_inc);
     OUTREG(RADEON_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16));
+    OUTREG(RADEON_OV0_P23_BLANK_LINES_AT_TOP, 0x00000fff | p23_blank_lines);
     OUTREG(RADEON_OV0_VID_BUF_PITCH0_VALUE, pitch);
-    OUTREG(RADEON_OV0_VID_BUF_PITCH1_VALUE, pitch);
+    OUTREG(RADEON_OV0_VID_BUF_PITCH1_VALUE, is_planar ? pitch >> 1 : pitch);
     OUTREG(RADEON_OV0_P1_X_START_END, (src_w + left - 1) | (left << 16));
-    left >>= 1; src_w >>= 1;
-    OUTREG(RADEON_OV0_P2_X_START_END, (src_w + left - 1) | (left << 16));
-    OUTREG(RADEON_OV0_P3_X_START_END, (src_w + left - 1) | (left << 16));
-    OUTREG(RADEON_OV0_VID_BUF0_BASE_ADRS, offset1 & 0xfffffff0);
-    OUTREG(RADEON_OV0_VID_BUF1_BASE_ADRS, offset2 & 0xfffffff0);
-    OUTREG(RADEON_OV0_VID_BUF2_BASE_ADRS, offset3 & 0xfffffff0);
-
-    RADEONWaitForFifo(pScrn, 9);
-    OUTREG(RADEON_OV0_VID_BUF3_BASE_ADRS, offset4 & 0xfffffff0);
-    OUTREG(RADEON_OV0_VID_BUF4_BASE_ADRS, offset1 & 0xfffffff0);
-    OUTREG(RADEON_OV0_VID_BUF5_BASE_ADRS, offset2 & 0xfffffff0);
+    src_w >>= 1;
+    OUTREG(RADEON_OV0_P2_X_START_END, (src_w + left - 1) | (((left >> 1) & 7) << 16));
+    OUTREG(RADEON_OV0_P3_X_START_END, (src_w + left - 1) | (((left >> 1) & 7) << 16));
+    OUTREG(RADEON_OV0_VID_BUF0_BASE_ADRS, offset1);
+    OUTREG(RADEON_OV0_VID_BUF1_BASE_ADRS, offset2);
+    OUTREG(RADEON_OV0_VID_BUF2_BASE_ADRS, offset3);
+
+    RADEONWaitForFifo(pScrn, 12);
+    OUTREG(RADEON_OV0_VID_BUF3_BASE_ADRS, offset4);
+    OUTREG(RADEON_OV0_VID_BUF4_BASE_ADRS, offset5);
+    OUTREG(RADEON_OV0_VID_BUF5_BASE_ADRS, offset6);
     OUTREG(RADEON_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
     OUTREG(RADEON_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
+    OUTREG(RADEON_OV0_P23_V_ACCUM_INIT, p23_v_accum_init);
     OUTREG(RADEON_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
 
    scale_cntl = RADEON_SCALER_ADAPTIVE_DEINT | RADEON_SCALER_DOUBLE_BUFFER 
@@ -2685,9 +2768,11 @@
                         | 0x10000000 
                         | scale_cntl);
                 break;
-        case FOURCC_YUY2:
         case FOURCC_YV12:
         case FOURCC_I420:
+ 		OUTREG(RADEON_OV0_SCALE_CNTL, RADEON_SCALER_SOURCE_YUV12 | scale_cntl);
+ 		break;
+        case FOURCC_YUY2:
         default:
                 OUTREG(RADEON_OV0_SCALE_CNTL,  RADEON_SCALER_SOURCE_VYUY422 
                         | ((info->ChipFamily>=CHIP_FAMILY_R200) ? RADEON_SCALER_TEMPORAL_DEINT :0) 
@@ -2714,8 +2799,9 @@
    RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
    INT32 xa, xb, ya, yb;
    unsigned char *dst_start;
-   int new_size, offset, s2offset, s3offset;
+   int new_size, offset, s1offset, s2offset, s3offset;
    int srcPitch, srcPitch2, dstPitch;
+   int d1line, d2line, d3line;
    int top, left, npixels, nlines, bpp;
    BoxRec dstBox;
    CARD32 tmp;
@@ -2735,7 +2821,8 @@
     */
 
    /* make the compiler happy */
-   s2offset = s3offset = srcPitch2 = 0;
+   s1offset = s2offset = s3offset = srcPitch2 = 0;
+   d2line = d3line = 0;
 
    if(src_w > (drw_w << 4))
 	drw_w = src_w >> 4;
@@ -2793,11 +2880,9 @@
 	break;
    case FOURCC_YV12:
    case FOURCC_I420:
-	dstPitch = ((width << 1) + 63) & ~63;
+    /* working, but bw only */
+	dstPitch = ((width + 31) & ~31);
 	srcPitch = (width + 3) & ~3;
-	s2offset = srcPitch * height;
-	srcPitch2 = ((width >> 1) + 3) & ~3;
-	s3offset = (srcPitch2 * (height >> 1)) + s2offset;
 	break;
    case FOURCC_UYVY:
    case FOURCC_YUY2:
@@ -2808,6 +2893,9 @@
    }
 
    new_size = dstPitch * height;
+   if (id == FOURCC_YV12 || id == FOURCC_I420) {
+      new_size *= 2;
+   }
    pPriv->video_offset = RADEONAllocateMemory(pScrn, &pPriv->video_memory,
 					      (pPriv->doubleBuffer ?
 					       (new_size * 2) : new_size));
@@ -2831,20 +2919,33 @@
    switch(id) {
     case FOURCC_YV12:
     case FOURCC_I420:
-	top &= ~1;
-	dst_start += left << 1;
-	tmp = ((top >> 1) * srcPitch2) + (left >> 1);
-	s2offset += tmp;
-	s3offset += tmp;
-	if(id == FOURCC_I420) {
-	   tmp = s2offset;
-	   s2offset = s3offset;
-	   s3offset = tmp;
-	}
-	nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top;
-	RADEONCopyMungedData(pScrn, buf + (top * srcPitch) + left,
-			     buf + s2offset, buf + s3offset, dst_start,
-			     srcPitch, srcPitch2, dstPitch, nlines, npixels);
+
+        d1line = top * dstPitch;
+	d2line = src_h * dstPitch + (d1line >> 2) - d1line;
+	d3line = d2line + ((src_h * dstPitch) >> 2);
+
+        s1offset = (top * srcPitch) + left;
+	s2offset = s1offset + (srcPitch * height);
+	srcPitch2 = ((width >> 1) + 3) & ~3;
+	s3offset = s2offset + ((srcPitch2 * height) >> 1);
+	/* hmm I think it should be the other way round strange */
+        if(id == FOURCC_YV12) {
+            tmp = s2offset;
+            s2offset = s3offset;
+            s3offset = tmp;
+        }
+
+        nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top;
+/*        RADEONCopyDataPlanar(pScrn,
+                             buf + s1offset, buf + s2offset, buf + s3offset,
+                             dst_start, dst_start + d2line, dst_start + d3line,
+                             srcPitch, srcPitch2, dstPitch, nlines, npixels);*/
+        RADEONCopyData(pScrn, buf + s1offset, dst_start, srcPitch, dstPitch, nlines, npixels, 1);
+        RADEONCopyData(pScrn, buf + s2offset, dst_start + d2line, srcPitch2,
+		dstPitch >> 1, nlines >> 1, npixels >> 1, 1);
+        RADEONCopyData(pScrn, buf + s3offset, dst_start + d3line, srcPitch2,
+		dstPitch >> 1, nlines >> 1, npixels >> 1, 1);
+	
 	break;
     case FOURCC_RGBT16:
     case FOURCC_RGB16:
@@ -2880,7 +2981,10 @@
 	    xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
     }
 
-    RADEONDisplayVideo(pScrn, pPriv, id, offset, offset, offset, offset, width, height, dstPitch,
+    /* FIXME: someone should look at these offsets, I don't think it makes sense how
+              they are handled throughout the source. */
+    RADEONDisplayVideo(pScrn, pPriv, id, offset, offset + d2line, offset + d3line,
+		     offset, offset + d2line, offset + d3line, width, height, dstPitch,
 		     xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h, METHOD_BOB);
 
     pPriv->videoStatus = CLIENT_VIDEO_ON;
@@ -3133,6 +3237,7 @@
     RADEONDisplayVideo(pScrn, portPriv, surface->id,
 		       surface->offsets[0], surface->offsets[0],
 		       surface->offsets[0], surface->offsets[0],
+		       surface->offsets[0], surface->offsets[0],
 		       surface->width, surface->height, surface->pitches[0],
 		       xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h, METHOD_BOB);
 
@@ -3413,7 +3518,9 @@
 	     	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
    }
 
-   RADEONDisplayVideo(pScrn, pPriv, id, offset1+top*srcPitch, offset2+top*srcPitch, offset3+top*srcPitch, offset4+top*srcPitch, width, height, dstPitch*mult/2,
+   RADEONDisplayVideo(pScrn, pPriv, id, offset1+top*srcPitch, offset2+top*srcPitch,
+		offset3+top*srcPitch, offset4+top*srcPitch, offset1+top*srcPitch,
+		offset2+top*srcPitch, width, height, dstPitch*mult/2,
                      xa, xb, ya, &dstBox, src_w, src_h*mult/2, drw_w, drw_h, pPriv->overlay_deinterlacing_method);
 
    RADEONWaitForFifo(pScrn, 1);