#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "radeon.h" #include "radeon_reg.h" #include "radeon_probe.h" #include "radeon_video.h" #include "xf86.h" #include "dixstruct.h" /* DPMS */ #ifdef HAVE_XEXTPROTO_71 #include #else #define DPMS_SERVER #include #endif #include #include "fourcc.h" #define OFF_DELAY 250 /* milliseconds */ #define FREE_DELAY 15000 #define OFF_TIMER 0x01 #define FREE_TIMER 0x02 #define CLIENT_VIDEO_ON 0x04 #define GET_PORT_PRIVATE(pScrn) \ (RADEONPortPrivPtr)((RADEONPTR(pScrn))->adaptor->pPortPrivates[0].ptr) static void radeon_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) { dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; } static void radeon_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) { if (crtc->enabled) { crtc_box->x1 = crtc->x; crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); crtc_box->y1 = crtc->y; crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); } else crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; } static int radeon_box_area(BoxPtr box) { return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); } static Bool radeon_crtc_is_enabled(xf86CrtcPtr crtc) { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; return drmmode_crtc->dpms_mode == DPMSModeOn; } xf86CrtcPtr radeon_pick_best_crtc(ScrnInfoPtr pScrn, int x1, int x2, int y1, int y2) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); int coverage, best_coverage, c; BoxRec box, crtc_box, cover_box; RROutputPtr primary_output = NULL; xf86CrtcPtr best_crtc = NULL, primary_crtc = NULL; if (!pScrn->vtSema) return NULL; box.x1 = x1; box.x2 = x2; box.y1 = y1; box.y2 = y2; best_coverage = 0; /* Prefer the CRTC of the primary output */ #ifdef HAS_DIXREGISTERPRIVATEKEY if (dixPrivateKeyRegistered(rrPrivKey)) #endif { primary_output = RRFirstOutput(pScrn->pScreen); } if (primary_output && primary_output->crtc) primary_crtc = primary_output->crtc->devPrivate; for (c = 0; c < xf86_config->num_crtc; c++) { xf86CrtcPtr crtc = xf86_config->crtc[c]; if (!radeon_crtc_is_enabled(crtc)) continue; radeon_crtc_box(crtc, &crtc_box); radeon_box_intersect(&cover_box, &crtc_box, &box); coverage = radeon_box_area(&cover_box); if (coverage > best_coverage || (coverage == best_coverage && crtc == primary_crtc)) { best_crtc = crtc; best_coverage = coverage; } } return best_crtc; } #ifndef HAVE_XF86CRTCCLIPVIDEOHELPER static xf86CrtcPtr radeon_covering_crtc(ScrnInfoPtr pScrn, BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); xf86CrtcPtr crtc, best_crtc; int coverage, best_coverage; int c; BoxRec crtc_box, cover_box; best_crtc = NULL; best_coverage = 0; crtc_box_ret->x1 = 0; crtc_box_ret->x2 = 0; crtc_box_ret->y1 = 0; crtc_box_ret->y2 = 0; for (c = 0; c < xf86_config->num_crtc; c++) { crtc = xf86_config->crtc[c]; radeon_crtc_box(crtc, &crtc_box); radeon_box_intersect(&cover_box, &crtc_box, box); coverage = radeon_box_area(&cover_box); if (coverage && crtc == desired) { *crtc_box_ret = crtc_box; return crtc; } else if (coverage > best_coverage) { *crtc_box_ret = crtc_box; best_crtc = crtc; best_coverage = coverage; } } return best_crtc; } static Bool radeon_crtc_clip_video_helper(ScrnInfoPtr pScrn, xf86CrtcPtr *crtc_ret, xf86CrtcPtr desired_crtc, BoxPtr dst, INT32 *xa, INT32 *xb, INT32 *ya, INT32 *yb, RegionPtr reg, INT32 width, INT32 height) { Bool ret; RegionRec crtc_region_local; RegionPtr crtc_region = reg; /* * For overlay video, compute the relevant CRTC and * clip video to that */ if (crtc_ret) { BoxRec crtc_box; xf86CrtcPtr crtc = radeon_covering_crtc(pScrn, dst, desired_crtc, &crtc_box); if (crtc) { REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1); crtc_region = &crtc_region_local; REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg); } *crtc_ret = crtc; } ret = xf86XVClipVideoHelper(dst, xa, xb, ya, yb, crtc_region, width, height); if (crtc_region != reg) REGION_UNINIT (pScreen, &crtc_region_local); return ret; } #endif void RADEONInitVideo(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; XF86VideoAdaptorPtr texturedAdaptor = NULL; int num_adaptors; /* no overlay or 3D on RN50 */ if (info->ChipFamily == CHIP_FAMILY_RV100 && !pRADEONEnt->HasCRTC2) return; num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); newAdaptors = malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *)); if (newAdaptors == NULL) return; memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); adaptors = newAdaptors; if ((info->ChipFamily < CHIP_FAMILY_RS400) || (info->directRenderingEnabled) ) { texturedAdaptor = RADEONSetupImageTexturedVideo(pScreen); if (texturedAdaptor != NULL) { adaptors[num_adaptors++] = texturedAdaptor; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up textured video\n"); } else xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set up textured video\n"); } else xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Textured video requires CP on R5xx/R6xx/R7xx/IGP\n"); if(num_adaptors) xf86XVScreenInit(pScreen, adaptors, num_adaptors); if(texturedAdaptor) { XF86MCAdaptorPtr xvmcAdaptor = RADEONCreateAdaptorXvMC(pScreen, texturedAdaptor->name); if(xvmcAdaptor) { if(!xf86XvMCScreenInit(pScreen, 1, &xvmcAdaptor)) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[XvMC] Failed to initialize extension.\n"); else xf86DrvMsg(pScrn->scrnIndex, X_INFO, "[XvMC] Extension initialized.\n"); } } if(newAdaptors) free(newAdaptors); } void RADEONCopyData( ScrnInfoPtr pScrn, unsigned char *src, unsigned char *dst, unsigned int srcPitch, unsigned int dstPitch, unsigned int h, unsigned int w, unsigned int bpp ){ /* Get the byte-swapping right for big endian systems */ if ( bpp == 2 ) { w *= 2; bpp = 1; } { int swap = RADEON_HOST_DATA_SWAP_NONE; #if X_BYTE_ORDER == X_BIG_ENDIAN switch(bpp) { case 2: swap = RADEON_HOST_DATA_SWAP_16BIT; break; case 4: swap = RADEON_HOST_DATA_SWAP_32BIT; break; } #endif w *= bpp; if (dstPitch == w && dstPitch == srcPitch) RADEONCopySwap(dst, src, h * dstPitch, swap); else { while (h--) { RADEONCopySwap(dst, src, w, swap); src += srcPitch; dst += dstPitch; } } } } void RADEONCopyMungedData( ScrnInfoPtr pScrn, unsigned char *src1, unsigned char *src2, unsigned char *src3, unsigned char *dst1, unsigned int srcPitch, unsigned int srcPitch2, unsigned int dstPitch, unsigned int h, unsigned int w ){ uint32_t *dst; uint8_t *s1, *s2, *s3; int i, j; w /= 2; for( j = 0; j < h; j++ ) { dst = (pointer)dst1; s1 = src1; s2 = src2; s3 = src3; i = w; while( i > 4 ) { dst[0] = cpu_to_le32(s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24)); dst[1] = cpu_to_le32(s1[2] | (s1[3] << 16) | (s3[1] << 8) | (s2[1] << 24)); dst[2] = cpu_to_le32(s1[4] | (s1[5] << 16) | (s3[2] << 8) | (s2[2] << 24)); dst[3] = cpu_to_le32(s1[6] | (s1[7] << 16) | (s3[3] << 8) | (s2[3] << 24)); dst += 4; s2 += 4; s3 += 4; s1 += 8; i -= 4; } while( i-- ) { dst[0] = cpu_to_le32(s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24)); dst++; s2++; s3++; s1 += 2; } dst1 += dstPitch; src1 += srcPitch; if( j & 1 ) { src2 += srcPitch2; src3 += srcPitch2; } } }