summaryrefslogtreecommitdiff
path: root/src/radeon_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/radeon_video.c')
-rw-r--r--src/radeon_video.c198
1 files changed, 134 insertions, 64 deletions
diff --git a/src/radeon_video.c b/src/radeon_video.c
index 6a910a1..e194706 100644
--- a/src/radeon_video.c
+++ b/src/radeon_video.c
@@ -2095,23 +2095,6 @@ RADEONCopyData(
}
}
-#ifdef XF86DRI
-static void RADEON_420_422(
- unsigned int *d,
- unsigned char *s1,
- unsigned char *s2,
- unsigned char *s3,
- unsigned int n
-)
-{
- while ( n ) {
- *(d++) = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
- s1+=2; s2++; s3++;
- n--;
- }
-}
-#endif
-
static void
RADEONCopyRGB24Data(
ScrnInfoPtr pScrn,
@@ -2188,6 +2171,24 @@ RADEONCopyRGB24Data(
}
}
+#if 0
+#ifdef XF86DRI
+static void RADEON_420_422(
+ unsigned int *d,
+ unsigned char *s1,
+ unsigned char *s2,
+ unsigned char *s3,
+ unsigned int n
+)
+{
+ while ( n ) {
+ *(d++) = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
+ s1+=2; s2++; s3++;
+ n--;
+ }
+}
+#endif
+
static void
RADEONCopyMungedData(
ScrnInfoPtr pScrn,
@@ -2286,6 +2287,7 @@ RADEONCopyMungedData(
#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
@@ -2401,6 +2403,7 @@ RADEONDisplayVideo(
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,
@@ -2414,7 +2417,8 @@ RADEONDisplayVideo(
CARD32 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;
@@ -2424,15 +2428,21 @@ RADEONDisplayVideo(
CARD32 dot_clock;
DisplayModePtr overlay_mode;
int is_rgb;
+ int is_planar;
int i;
CARD32 scale_cntl;
double dsr;
int tap_set;
int predownscale=0;
int src_w_d;
+ int leftuv = 0;
- 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:
@@ -2441,7 +2451,7 @@ RADEONDisplayVideo(
break;
default:
break;
- }
+ }
/* Unlike older Mach64 chips, RADEON has only two ECP settings: 0 for PIXCLK < 175Mhz, and 1 (divide by 2)
for higher clocks, sure makes life nicer
@@ -2537,7 +2547,8 @@ RADEONDisplayVideo(
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;
@@ -2560,16 +2571,34 @@ RADEONDisplayVideo(
/* 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 >> 16) & ~15);
+ offset2 += ((left >> 16) & ~31) >> 1;
+ offset3 += ((left >> 16) & ~31) >> 1;
+ offset4 += ((left >> 16) & ~15);
+ offset5 += ((left >> 16) & ~31) >> 1;
+ offset6 += ((left >> 16) & ~31) >> 1;
+ 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 {
+ /* is this really correct for non-2-byte formats? */
+ offset1 += ((left >> 16) & ~7) << 1;
+ offset2 += ((left >> 16) & ~7) << 1;
+ offset3 += ((left >> 16) & ~7) << 1;
+ offset4 += ((left >> 16) & ~7) << 1;
+ offset5 += ((left >> 16) & ~7) << 1;
+ offset6 += ((left >> 16) & ~7) << 1;
+ }
if (info->IsSecondary) {
offset1 += info->FbMapSize;
offset2 += info->FbMapSize;
- offset3 += info->FbMapSize;
- offset4 += info->FbMapSize;
+ offset3 += info->FbMapSize;
+ offset4 += info->FbMapSize;
+ offset5 += info->FbMapSize;
+ offset6 += info->FbMapSize;
}
tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
@@ -2584,7 +2613,23 @@ RADEONDisplayVideo(
p1_v_accum_init = ((tmp << 4) & 0x03ff8000) |
(((deinterlacing_method!=METHOD_WEAVE)&&!is_rgb)?0x03:0x01);
- left = (left >> 16) & 7;
+ if (is_planar) {
+ p23_v_accum_init = ((tmp << 4) & 0x03ff8000) |
+ ((deinterlacing_method != METHOD_WEAVE) ? 0x03 : 0x01);
+ p23_blank_lines = (((src_h >> 1) - 1) << 16);
+ }
+ else {
+ p23_v_accum_init = 0;
+ p23_blank_lines = 0;
+ }
+
+ if (is_planar) {
+ leftuv = ((left >> 16) >> 1) & 15;
+ left = (left >> 16) & 15;
+ }
+ else {
+ left = (left >> 16) & 7;
+ }
RADEONWaitForFifo(pScrn, 2);
OUTREG(RADEON_OV0_REG_LOAD_CNTL, RADEON_REG_LD_CTL_LOCK);
@@ -2654,25 +2699,27 @@ RADEONDisplayVideo(
((TapCoeffs[tap_set].coeff[i][3] &0xf)<<24));
}
- RADEONWaitForFifo(pScrn, 10);
+ RADEONWaitForFifo(pScrn, 11);
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, 0x000007ff | 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);
+ src_w >>= 1;
+ OUTREG(RADEON_OV0_P2_X_START_END, (src_w + leftuv - 1) | (leftuv << 16));
+ OUTREG(RADEON_OV0_P3_X_START_END, (src_w + leftuv - 1) | (leftuv << 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, 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);
+ 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
@@ -2690,9 +2737,11 @@ RADEONDisplayVideo(
case FOURCC_RGBT16:
scale_cntl |= RADEON_SCALER_SOURCE_15BPP | RADEON_SCALER_LIN_TRANS_BYPASS;
break;
- case FOURCC_YUY2:
case FOURCC_YV12:
case FOURCC_I420:
+ scale_cntl |= RADEON_SCALER_SOURCE_YUV12;
+ break;
+ case FOURCC_YUY2:
default:
scale_cntl |= RADEON_SCALER_SOURCE_VYUY422
| ((info->ChipFamily >= CHIP_FAMILY_R200) ? RADEON_SCALER_TEMPORAL_DEINT : 0);
@@ -2733,6 +2782,7 @@ RADEONPutImage(
unsigned char *dst_start;
int new_size, offset, s2offset, s3offset;
int srcPitch, srcPitch2, dstPitch;
+ int d2line, d3line;
int top, left, npixels, nlines, bpp;
BoxRec dstBox;
CARD32 tmp;
@@ -2750,6 +2800,7 @@ RADEONPutImage(
/* make the compiler happy */
s2offset = s3offset = srcPitch2 = 0;
+ d2line = d3line = 0;
if(src_w > (drw_w << 4))
drw_w = src_w >> 4;
@@ -2804,11 +2855,10 @@ RADEONPutImage(
break;
case FOURCC_YV12:
case FOURCC_I420:
- dstPitch = ((width << 1) + 63) & ~63;
- srcPitch = (width + 3) & ~3;
- s2offset = srcPitch * height;
- srcPitch2 = ((width >> 1) + 3) & ~3;
- s3offset = (srcPitch2 * (height >> 1)) + s2offset;
+ /* need 16bytes alignment for u,v plane, so 2 times that for width
+ but blitter needs 64bytes alignment */
+ dstPitch = ((width + 127) & ~127);
+ srcPitch = width;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
@@ -2819,6 +2869,9 @@ RADEONPutImage(
}
new_size = dstPitch * height;
+ if (id == FOURCC_YV12 || id == FOURCC_I420) {
+ new_size += (dstPitch >> 1) * height;
+ }
pPriv->video_offset = RADEONAllocateMemory(pScrn, &pPriv->video_memory,
(pPriv->doubleBuffer ?
(new_size * 2) : new_size));
@@ -2840,22 +2893,33 @@ RADEONPutImage(
dst_start = info->FB + offset;
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);
+ case FOURCC_YV12:
+ case FOURCC_I420:
+/* meh. Such a mess just for someone who wants to watch half the video clipped */
+ /* odd number of pixels? That may not work correctly */
+ srcPitch2 = width >> 1;
+ /* odd number of lines? See above... */
+ s2offset = (srcPitch * height);
+ s3offset = s2offset + srcPitch2 * (height >> 1);
+ s2offset += (top >> 1) * srcPitch2 + (left >> 1);
+ s3offset += (top >> 1) * srcPitch2 + (left >> 1);
+ d2line = (height * dstPitch);
+ d3line = d2line + (height >> 1) * (dstPitch >> 1);
+ nlines = ((yb + 0xffff) >> 16) - top;
+ d2line += (top >> 1) * (dstPitch >> 1) - (top * dstPitch);
+ d3line += (top >> 1) * (dstPitch >> 1) - (top * dstPitch);
+ if(id == FOURCC_YV12) {
+ tmp = s2offset;
+ s2offset = s3offset;
+ s3offset = tmp;
+ }
+ RADEONCopyData(pScrn, buf + (top * srcPitch) + left, dst_start + left,
+ srcPitch, dstPitch, nlines, npixels, 1);
+ RADEONCopyData(pScrn, buf + s2offset, dst_start + d2line + (left >> 1),
+ srcPitch2, dstPitch >> 1, nlines >> 1, npixels >> 1, 1);
+ RADEONCopyData(pScrn, buf + s3offset, dst_start + d3line + (left >> 1),
+ srcPitch2, dstPitch >> 1, nlines >> 1, npixels >> 1, 1);
+
break;
case FOURCC_RGBT16:
case FOURCC_RGB16:
@@ -2891,7 +2955,10 @@ RADEONPutImage(
RADEONFillKeyHelper(pDraw, 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;
@@ -3156,6 +3223,7 @@ RADEONDisplaySurface(
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);
@@ -3437,7 +3505,9 @@ RADEONPutVideo(
RADEONFillKeyHelper(pDraw, 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);