1354 lines
38 KiB
C
1354 lines
38 KiB
C
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "xf86.h"
|
|
#include "tdfx.h"
|
|
#include "dixstruct.h"
|
|
|
|
#include <X11/extensions/Xv.h>
|
|
#include "fourcc.h"
|
|
|
|
static Atom xvColorKey, xvFilterQuality;
|
|
|
|
/* These should move into tdfxdefs.h with better names */
|
|
#define YUV_Y_BASE 0xC00000
|
|
#define YUV_U_BASE 0xD00000
|
|
#define YUV_V_BASE 0xE00000
|
|
|
|
#define SST_2D_FORMAT_YUYV 0x8
|
|
#define SST_2D_FORMAT_UYVY 0x9
|
|
|
|
#define YUVBASEADDR 0x80100
|
|
#define YUVSTRIDE 0x80104
|
|
#define VIDPROCCFGMASK 0xa2e3eb6c
|
|
|
|
#define OFF_DELAY 250 /* milliseconds */
|
|
#define FREE_DELAY 15000
|
|
|
|
#define OFF_TIMER 0x01
|
|
#define FREE_TIMER 0x02
|
|
#define CLIENT_VIDEO_ON 0x04
|
|
#define TIMER_MASK (OFF_TIMER | FREE_TIMER)
|
|
|
|
#define TDFX_MAX_OVERLAY_PORTS 1
|
|
#define TDFX_MAX_TEXTURE_PORTS 32
|
|
|
|
#define GET_PORT_PRIVATE(pScrn) \
|
|
(TDFXPortPrivPtr)((TDFXPTR(pScrn))->overlayAdaptor->pPortPrivates[0].ptr)
|
|
|
|
/* Needed for attribute atoms */
|
|
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
|
|
|
|
/*
|
|
* PROTOTYPES
|
|
*/
|
|
|
|
static FBAreaPtr TDFXAllocateMemoryArea (ScrnInfoPtr pScrn, FBAreaPtr area, int width, int height);
|
|
static FBLinearPtr TDFXAllocateMemoryLinear (ScrnInfoPtr pScrn, FBLinearPtr linear, int size);
|
|
static void TDFXVideoTimerCallback(ScrnInfoPtr pScrn, Time time);
|
|
|
|
static XF86VideoAdaptorPtr TDFXSetupImageVideoTexture(ScreenPtr);
|
|
static int TDFXSetPortAttributeTexture(ScrnInfoPtr, Atom, INT32, pointer);
|
|
static int TDFXGetPortAttributeTexture(ScrnInfoPtr, Atom ,INT32 *, pointer);
|
|
static int TDFXPutImageTexture(ScrnInfoPtr, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, Bool, RegionPtr, pointer, DrawablePtr);
|
|
static void TDFXStopVideoTexture(ScrnInfoPtr, pointer, Bool);
|
|
|
|
static XF86VideoAdaptorPtr TDFXSetupImageVideoOverlay(ScreenPtr);
|
|
static int TDFXSetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
|
|
static int TDFXGetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer);
|
|
static int TDFXPutImageOverlay(ScrnInfoPtr, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, Bool, RegionPtr, pointer, DrawablePtr);
|
|
static void TDFXStopVideoOverlay(ScrnInfoPtr, pointer, Bool);
|
|
static void TDFXResetVideoOverlay(ScrnInfoPtr);
|
|
|
|
static void TDFXQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, unsigned int *, unsigned int *, pointer);
|
|
static int TDFXQueryImageAttributes(ScrnInfoPtr, int, unsigned short *, unsigned short *, int *, int *);
|
|
|
|
static void TDFXInitOffscreenImages(ScreenPtr);
|
|
|
|
/*
|
|
* ADAPTOR INFORMATION
|
|
*/
|
|
|
|
static XF86VideoEncodingRec OverlayEncoding[] =
|
|
{
|
|
{ 0, "XV_IMAGE", 2048, 2048, {1, 1} }
|
|
};
|
|
|
|
static XF86VideoEncodingRec TextureEncoding[] =
|
|
{
|
|
{ 0, "XV_IMAGE", 1024, 1024, {1, 1} }
|
|
};
|
|
|
|
static XF86VideoFormatRec OverlayFormats[] =
|
|
{
|
|
{8, TrueColor}, {8, DirectColor}, {8, PseudoColor},
|
|
{8, GrayScale}, {8, StaticGray}, {8, StaticColor},
|
|
{15, TrueColor}, {16, TrueColor}, {24, TrueColor},
|
|
{15, DirectColor}, {16, DirectColor}, {24, DirectColor}
|
|
};
|
|
|
|
static XF86VideoFormatRec TextureFormats[] =
|
|
{
|
|
{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
|
|
};
|
|
|
|
static XF86AttributeRec OverlayAttributes[] =
|
|
{
|
|
{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
|
|
{XvSettable | XvGettable, 0, 1, "XV_FILTER_QUALITY"}
|
|
};
|
|
|
|
static XF86AttributeRec TextureAttributes[] =
|
|
{
|
|
{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
|
|
{XvSettable | XvGettable, 0, 1, "XV_FILTER_QUALITY"}
|
|
};
|
|
|
|
static XF86ImageRec OverlayImages[] =
|
|
{
|
|
XVIMAGE_YUY2, XVIMAGE_UYVY, XVIMAGE_YV12, XVIMAGE_I420
|
|
};
|
|
|
|
static XF86ImageRec TextureImages[] =
|
|
{
|
|
XVIMAGE_YV12, XVIMAGE_I420
|
|
};
|
|
|
|
/*
|
|
* COMMON SETUP FUNCTIONS
|
|
*/
|
|
|
|
void TDFXInitVideo(ScreenPtr pScreen)
|
|
{
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
|
|
XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
|
|
XF86VideoAdaptorPtr newAdaptor = NULL;
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
int num_adaptors;
|
|
|
|
/* The hardware can't convert YUV->8 bit color */
|
|
if(pTDFX->cpp == 1)
|
|
return;
|
|
|
|
if (!pTDFX->TextureXvideo) {
|
|
/* Offscreen support for Overlay only */
|
|
TDFXInitOffscreenImages(pScreen);
|
|
|
|
/* Overlay adaptor */
|
|
newAdaptor = TDFXSetupImageVideoOverlay(pScreen);
|
|
} else {
|
|
/* Texture adaptor */
|
|
newAdaptor = TDFXSetupImageVideoTexture(pScreen);
|
|
}
|
|
|
|
num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
|
|
|
|
if(newAdaptor) {
|
|
if (!num_adaptors) {
|
|
num_adaptors = 1;
|
|
adaptors = &newAdaptor;
|
|
} else {
|
|
newAdaptors =
|
|
malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
|
|
if(newAdaptors) {
|
|
memcpy(newAdaptors, adaptors, num_adaptors *
|
|
sizeof(XF86VideoAdaptorPtr));
|
|
newAdaptors[num_adaptors] = newAdaptor;
|
|
adaptors = newAdaptors;
|
|
num_adaptors++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(num_adaptors)
|
|
xf86XVScreenInit(pScreen, adaptors, num_adaptors);
|
|
|
|
if(newAdaptors)
|
|
free(newAdaptors);
|
|
}
|
|
|
|
|
|
void TDFXCloseVideo (ScreenPtr pScreen)
|
|
{
|
|
}
|
|
|
|
|
|
static XF86VideoAdaptorPtr
|
|
TDFXAllocAdaptor(ScrnInfoPtr pScrn, int numberPorts)
|
|
{
|
|
XF86VideoAdaptorPtr adapt;
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
TDFXPortPrivPtr pPriv;
|
|
|
|
if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
|
|
return NULL;
|
|
|
|
if(!(pPriv = calloc(1, sizeof(TDFXPortPrivRec) + (numberPorts * sizeof(DevUnion)))))
|
|
{
|
|
free(adapt);
|
|
return NULL;
|
|
}
|
|
|
|
adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
|
|
adapt->pPortPrivates[0].ptr = (pointer)pPriv;
|
|
|
|
xvColorKey = MAKE_ATOM("XV_COLORKEY");
|
|
xvFilterQuality = MAKE_ATOM("XV_FILTER_QUALITY");
|
|
|
|
pPriv->colorKey = pTDFX->videoKey;
|
|
pPriv->videoStatus = 0;
|
|
pPriv->filterQuality = 1;
|
|
|
|
return adapt;
|
|
}
|
|
|
|
|
|
static XF86VideoAdaptorPtr
|
|
TDFXSetupImageVideoOverlay(ScreenPtr pScreen)
|
|
{
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
TDFXPortPrivPtr pPriv;
|
|
XF86VideoAdaptorPtr adapt;
|
|
|
|
if(!(adapt = TDFXAllocAdaptor(pScrn, TDFX_MAX_OVERLAY_PORTS)))
|
|
return NULL;
|
|
|
|
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
|
|
adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
|
|
adapt->name = "3dfx Video Overlay";
|
|
adapt->nPorts = TDFX_MAX_OVERLAY_PORTS;
|
|
adapt->nEncodings = sizeof(OverlayEncoding) / sizeof(XF86VideoEncodingRec);
|
|
adapt->pEncodings = OverlayEncoding;
|
|
adapt->nFormats = sizeof(OverlayFormats) / sizeof(XF86VideoFormatRec);
|
|
adapt->pFormats = OverlayFormats;
|
|
adapt->nAttributes = sizeof(OverlayAttributes) / sizeof(XF86AttributeRec);
|
|
adapt->pAttributes = OverlayAttributes;
|
|
adapt->nImages = sizeof(OverlayImages) / sizeof(XF86ImageRec);
|
|
adapt->pImages = OverlayImages;
|
|
adapt->PutVideo = NULL;
|
|
adapt->PutStill = NULL;
|
|
adapt->GetVideo = NULL;
|
|
adapt->GetStill = NULL;
|
|
adapt->StopVideo = TDFXStopVideoOverlay;
|
|
adapt->SetPortAttribute = TDFXSetPortAttributeOverlay;
|
|
adapt->GetPortAttribute = TDFXGetPortAttributeOverlay;
|
|
adapt->QueryBestSize = TDFXQueryBestSize;
|
|
adapt->PutImage = TDFXPutImageOverlay;
|
|
adapt->QueryImageAttributes = TDFXQueryImageAttributes;
|
|
|
|
pTDFX->overlayAdaptor = adapt;
|
|
|
|
pPriv = (TDFXPortPrivPtr)(adapt->pPortPrivates[0].ptr);
|
|
REGION_NULL(pScreen, &(pPriv->clip));
|
|
|
|
TDFXResetVideoOverlay(pScrn);
|
|
|
|
return adapt;
|
|
}
|
|
|
|
static XF86VideoAdaptorPtr
|
|
TDFXSetupImageVideoTexture(ScreenPtr pScreen)
|
|
{
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
XF86VideoAdaptorPtr adapt;
|
|
int i;
|
|
|
|
if(!(adapt = TDFXAllocAdaptor(pScrn, TDFX_MAX_TEXTURE_PORTS)))
|
|
return NULL;
|
|
|
|
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
|
|
adapt->flags = VIDEO_OVERLAID_IMAGES;
|
|
adapt->name = "3dfx Video Texture";
|
|
adapt->nPorts = TDFX_MAX_TEXTURE_PORTS;
|
|
adapt->nEncodings = sizeof(TextureEncoding) / sizeof(XF86VideoEncodingRec);
|
|
adapt->pEncodings = TextureEncoding;
|
|
adapt->nFormats = sizeof(TextureFormats) / sizeof(XF86VideoFormatRec);
|
|
adapt->pFormats = TextureFormats;
|
|
adapt->nAttributes = sizeof(TextureAttributes) / sizeof(XF86AttributeRec);
|
|
adapt->pAttributes = TextureAttributes;
|
|
adapt->nImages = sizeof(TextureImages) / sizeof(XF86ImageRec);
|
|
adapt->pImages = TextureImages;
|
|
adapt->PutVideo = NULL;
|
|
adapt->PutStill = NULL;
|
|
adapt->GetVideo = NULL;
|
|
adapt->GetStill = NULL;
|
|
adapt->StopVideo = TDFXStopVideoTexture;
|
|
adapt->SetPortAttribute = TDFXSetPortAttributeTexture;
|
|
adapt->GetPortAttribute = TDFXGetPortAttributeTexture;
|
|
adapt->QueryBestSize = TDFXQueryBestSize;
|
|
adapt->PutImage = TDFXPutImageTexture;
|
|
adapt->QueryImageAttributes = TDFXQueryImageAttributes;
|
|
|
|
for(i = 0; i < TDFX_MAX_TEXTURE_PORTS; i++)
|
|
adapt->pPortPrivates[i].val = i;
|
|
|
|
pTDFX->textureAdaptor = adapt;
|
|
|
|
return adapt;
|
|
}
|
|
|
|
|
|
/*
|
|
* MISCELLANEOUS ROUTINES
|
|
*/
|
|
|
|
static int
|
|
TDFXQueryImageAttributes(
|
|
ScrnInfoPtr pScrn,
|
|
int id,
|
|
unsigned short *w, unsigned short *h,
|
|
int *pitches, int *offsets
|
|
){
|
|
int size, tmp;
|
|
|
|
if(*w > 1024) *w = 1024;
|
|
if(*h > 1024) *h = 1024;
|
|
|
|
*w = (*w + 1) & ~1;
|
|
if(offsets) offsets[0] = 0;
|
|
|
|
switch(id) {
|
|
case FOURCC_YV12:
|
|
case FOURCC_I420:
|
|
*h = (*h + 1) & ~1;
|
|
size = (*w + 3) & ~3;
|
|
if(pitches) pitches[0] = size;
|
|
size *= *h;
|
|
if(offsets) offsets[1] = size;
|
|
tmp = ((*w >> 1) + 3) & ~3;
|
|
if(pitches) pitches[1] = pitches[2] = tmp;
|
|
tmp *= (*h >> 1);
|
|
size += tmp;
|
|
if(offsets) offsets[2] = size;
|
|
size += tmp;
|
|
break;
|
|
case FOURCC_UYVY:
|
|
case FOURCC_YUY2:
|
|
default:
|
|
size = *w << 1;
|
|
if(pitches) pitches[0] = size;
|
|
size *= *h;
|
|
break;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
static int
|
|
TDFXSetPortAttributeOverlay(
|
|
ScrnInfoPtr pScrn,
|
|
Atom attribute,
|
|
INT32 value,
|
|
pointer data
|
|
){
|
|
|
|
TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data;
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
|
|
if(attribute == xvColorKey) {
|
|
pPriv->colorKey = value;
|
|
pTDFX->writeLong(pTDFX, VIDCHROMAMIN, pPriv->colorKey);
|
|
pTDFX->writeLong(pTDFX, VIDCHROMAMAX, pPriv->colorKey);
|
|
REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
|
|
} else if(attribute == xvFilterQuality) {
|
|
if((value < 0) || (value > 1))
|
|
return BadValue;
|
|
pPriv->filterQuality = value;
|
|
} else return BadMatch;
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
TDFXGetPortAttributeOverlay(
|
|
ScrnInfoPtr pScrn,
|
|
Atom attribute,
|
|
INT32 *value,
|
|
pointer data
|
|
){
|
|
TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data;
|
|
|
|
if(attribute == xvColorKey) {
|
|
*value = pPriv->colorKey;
|
|
} else if(attribute == xvFilterQuality) {
|
|
*value = pPriv->filterQuality;
|
|
} else return BadMatch;
|
|
|
|
return Success;
|
|
}
|
|
|
|
|
|
static int
|
|
TDFXSetPortAttributeTexture(
|
|
ScrnInfoPtr pScrn,
|
|
Atom attribute,
|
|
INT32 value,
|
|
pointer data
|
|
) {
|
|
return Success;
|
|
}
|
|
|
|
|
|
static int
|
|
TDFXGetPortAttributeTexture(
|
|
ScrnInfoPtr pScrn,
|
|
Atom attribute,
|
|
INT32 *value,
|
|
pointer data
|
|
){
|
|
return Success;
|
|
}
|
|
|
|
|
|
static void
|
|
TDFXQueryBestSize(
|
|
ScrnInfoPtr pScrn,
|
|
Bool motion,
|
|
short vid_w, short vid_h,
|
|
short drw_w, short drw_h,
|
|
unsigned int *p_w, unsigned int *p_h,
|
|
pointer data
|
|
){
|
|
if(vid_w > drw_w) drw_w = vid_w;
|
|
if(vid_h > drw_h) drw_h = vid_h;
|
|
|
|
*p_w = drw_w;
|
|
*p_h = drw_h;
|
|
}
|
|
|
|
|
|
static void
|
|
TDFXCopyData(
|
|
unsigned char *src,
|
|
unsigned char *dst,
|
|
int srcPitch,
|
|
int dstPitch,
|
|
int h,
|
|
int w
|
|
){
|
|
#if X_BYTE_ORDER == X_BIG_ENDIAN
|
|
w >>= 1;
|
|
while(h--) {
|
|
int i;
|
|
for (i=0; i<w; i++)
|
|
((unsigned long *)dst)[i]=BE_WSWAP32(((unsigned long *)src)[i]);
|
|
src += srcPitch;
|
|
dst += dstPitch;
|
|
}
|
|
#else
|
|
w <<= 1;
|
|
while(h--) {
|
|
memcpy(dst, src, w);
|
|
src += srcPitch;
|
|
dst += dstPitch;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
TDFXCopyMungedData(
|
|
unsigned char *src1,
|
|
unsigned char *src2,
|
|
unsigned char *src3,
|
|
unsigned char *dst1,
|
|
int srcPitch,
|
|
int srcPitch2,
|
|
int dstPitch,
|
|
int h,
|
|
int w
|
|
){
|
|
CARD32 *dst;
|
|
CARD8 *s1, *s2, *s3;
|
|
int i, j;
|
|
|
|
w >>= 1;
|
|
|
|
for(j = 0; j < h; j++) {
|
|
dst = (CARD32*)dst1;
|
|
s1 = src1; s2 = src2; s3 = src3;
|
|
i = w;
|
|
while(i > 4) {
|
|
dst[0] = BE_WSWAP32(s1[0] | (s1[1] << 16) | (s3[0] << 8) |
|
|
(s2[0] << 24));
|
|
dst[1] = BE_WSWAP32(s1[2] | (s1[3] << 16) | (s3[1] << 8) |
|
|
(s2[1] << 24));
|
|
dst[2] = BE_WSWAP32(s1[4] | (s1[5] << 16) | (s3[2] << 8) |
|
|
(s2[2] << 24));
|
|
dst[3] = BE_WSWAP32(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] = BE_WSWAP32(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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* TEXTURE DRAWING FUNCTIONS
|
|
*/
|
|
|
|
|
|
static void
|
|
TDFXStopVideoTexture(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
|
|
{
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
|
|
if (cleanup) {
|
|
if(pTDFX->textureBuffer) {
|
|
xf86FreeOffscreenArea(pTDFX->textureBuffer);
|
|
pTDFX->textureBuffer = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
TDFXScreenToScreenYUVStretchBlit (ScrnInfoPtr pScrn,
|
|
short src_x1, short src_y1,
|
|
short src_x2, short src_y2,
|
|
short dst_x1, short dst_y1,
|
|
short dst_x2, short dst_y2)
|
|
{
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
/* reformulate the paramaters the way the hardware wants them */
|
|
INT32 src_x = src_x1 & 0x1FFF;
|
|
INT32 src_y = src_y1 & 0x1FFF;
|
|
INT32 dst_x = dst_x1 & 0x1FFF;
|
|
INT32 dst_y = dst_y1 & 0x1FFF;
|
|
INT32 src_w = (src_x2 - src_x1) & 0x1FFF;
|
|
INT32 src_h = (src_y2 - src_y1) & 0x1FFF;
|
|
INT32 dst_w = (dst_x2 - dst_x1) & 0x1FFF;
|
|
INT32 dst_h = (dst_y2 - dst_y1) & 0x1FFF;
|
|
|
|
/* Setup for blit src and dest */
|
|
TDFXMakeRoom(pTDFX, 4);
|
|
DECLARE(SSTCP_DSTSIZE|SSTCP_SRCSIZE|SSTCP_DSTXY|SSTCP_COMMAND/*|SSTCP_COMMANDEXTRA*/);
|
|
/* TDFXWriteLong(pTDFX, SST_2D_COMMANDEXTRA, SST_COMMANDEXTRA_VSYNC);*/
|
|
TDFXWriteLong(pTDFX, SST_2D_SRCSIZE, src_w | (src_h<<16));
|
|
TDFXWriteLong(pTDFX, SST_2D_DSTSIZE, dst_w | (dst_h<<16));
|
|
TDFXWriteLong(pTDFX, SST_2D_DSTXY, dst_x | (dst_y<<16));
|
|
TDFXWriteLong(pTDFX, SST_2D_COMMAND, SST_2D_SCRNTOSCRNSTRETCH | 0xCC000000);
|
|
/* Write to the launch area to start the blit */
|
|
TDFXMakeRoom(pTDFX, 1);
|
|
DECLARE_LAUNCH(1, 0);
|
|
TDFXWriteLong(pTDFX, SST_2D_LAUNCH, (src_x<<1) | (src_y<<16));
|
|
/* Wait for it to happen */
|
|
TDFXSendNOPFifo2D(pScrn);
|
|
}
|
|
|
|
|
|
static void
|
|
YUVPlanarToPacked (ScrnInfoPtr pScrn,
|
|
short src_x, short src_y,
|
|
short src_h, short src_w,
|
|
int id, unsigned char *buf,
|
|
short width, short height,
|
|
FBAreaPtr fbarea)
|
|
{
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
unsigned char *psrc, *pdst;
|
|
int count;
|
|
int baseaddr;
|
|
INT32 yuvBaseAddr, yuvStride;
|
|
|
|
/* Save these registers so I can restore them when we are done. */
|
|
yuvBaseAddr = TDFXReadLongMMIO(pTDFX, YUVBASEADDR);
|
|
yuvStride = TDFXReadLongMMIO(pTDFX, YUVSTRIDE);
|
|
|
|
/* Set yuvBaseAddress and yuvStride. */
|
|
baseaddr = pTDFX->fbOffset + pTDFX->cpp * fbarea->box.x1 + pTDFX->stride * fbarea->box.y1;
|
|
TDFXWriteLongMMIO(pTDFX, YUVSTRIDE, pTDFX->stride);
|
|
TDFXWriteLongMMIO(pTDFX, YUVBASEADDR, baseaddr);
|
|
|
|
/* Copy Y plane (twice as much Y as U or V) */
|
|
psrc = buf;
|
|
psrc += (src_x & ~0x1) + src_y * width;
|
|
pdst = pTDFX->MMIOBase[0] + YUV_Y_BASE;
|
|
TDFXCopyData(psrc, pdst, width, 1024, src_h, src_w + (src_x & 0x1));
|
|
|
|
/* Copy V plane */
|
|
psrc = buf + width * height;
|
|
psrc += (src_x >> 1) + (src_y >> 1) * (width >> 1);
|
|
pdst = pTDFX->MMIOBase[0] + YUV_V_BASE;
|
|
TDFXCopyData(psrc, pdst, width >> 1, 1024, src_h >> 1, src_w >> 1);
|
|
|
|
/* Copy U plane */
|
|
psrc = buf + width * height + (width >> 1) * (height >> 1);
|
|
psrc += (src_x >> 1) + (src_y >> 1) * (width >> 1);
|
|
pdst = pTDFX->MMIOBase[0] + YUV_U_BASE;
|
|
TDFXCopyData(psrc, pdst, width >> 1, 1024, src_h >> 1, src_w >> 1);
|
|
|
|
/* IDLE until the copy finished, timeout for safety */
|
|
for (count = 0; count < 1000; count++)
|
|
if (!((TDFXReadLongMMIO(pTDFX, STATUS) & SST_BUSY)))
|
|
break;
|
|
|
|
/* Restore trashed registers */
|
|
TDFXWriteLongMMIO(pTDFX, YUVBASEADDR, yuvBaseAddr);
|
|
TDFXWriteLongMMIO(pTDFX, YUVSTRIDE, yuvStride);
|
|
|
|
/* Wait for it to happen */
|
|
TDFXSendNOPFifo2D(pScrn);
|
|
}
|
|
|
|
|
|
static int
|
|
TDFXPutImageTexture(
|
|
ScrnInfoPtr pScrn,
|
|
short src_x, short src_y,
|
|
short drw_x, short drw_y,
|
|
short src_w, short src_h,
|
|
short drw_w, short drw_h,
|
|
int id, unsigned char* buf,
|
|
short width, short height,
|
|
Bool sync,
|
|
RegionPtr clipBoxes, pointer data,
|
|
DrawablePtr pDraw
|
|
)
|
|
{
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
BoxPtr pbox;
|
|
int nbox;
|
|
int format;
|
|
|
|
TDFXTRACE("TDFXPutImageTexture(src_x=%d, src_y=%d, drw_x=%d, drw_y=%d, .. sync=%d\n",
|
|
src_x, src_y, drw_x, drw_y, sync);
|
|
|
|
/* Check the source format */
|
|
if (id == FOURCC_YV12) format = SST_2D_FORMAT_YUYV;
|
|
else if (id == FOURCC_UYVY) format = SST_2D_FORMAT_UYVY;
|
|
else return BadAlloc;
|
|
|
|
/* Get a buffer to store the packed YUV data */
|
|
if (!(pTDFX->textureBuffer = TDFXAllocateMemoryArea(pScrn, pTDFX->textureBuffer, src_w, src_h)))
|
|
return BadAlloc;
|
|
|
|
/* Pack the YUV data in offscreen memory using YUV framebuffer (0x[CDE]0000) */
|
|
YUVPlanarToPacked (pScrn, src_x, src_y, src_h, src_w,
|
|
id, buf, width, height,
|
|
pTDFX->textureBuffer);
|
|
|
|
/* Setup source and destination pixel formats (yuv -> rgb) */
|
|
TDFXMakeRoom(pTDFX, 2);
|
|
DECLARE(SSTCP_SRCFORMAT|SSTCP_DSTFORMAT);
|
|
TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, pTDFX->stride|((pTDFX->cpp+1)<<16));
|
|
TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, pTDFX->stride|((format)<<16));
|
|
|
|
/* Blit packed YUV data from offscreen memory, respecting clips */
|
|
#define SRC_X1 (pTDFX->textureBuffer->box.x1)
|
|
#define SRC_Y1 (pTDFX->textureBuffer->box.y1)
|
|
#define SCALEX(dx) ((int)(((dx) * src_w) / drw_w))
|
|
#define SCALEY(dy) ((int)(((dy) * src_h) / drw_h))
|
|
for (nbox = REGION_NUM_RECTS(clipBoxes),
|
|
pbox = REGION_RECTS(clipBoxes); nbox > 0; nbox--, pbox++)
|
|
{
|
|
TDFXScreenToScreenYUVStretchBlit (pScrn,
|
|
SRC_X1 + SCALEX(pbox->x1 - drw_x),
|
|
SRC_Y1 + SCALEY(pbox->y1 - drw_y),
|
|
SRC_X1 + SCALEX(pbox->x2 - drw_x),
|
|
SRC_Y1 + SCALEY(pbox->y2 - drw_y),
|
|
pbox->x1, pbox->y1,
|
|
pbox->x2, pbox->y2);
|
|
}
|
|
|
|
/* Restore the WAX registers we trashed */
|
|
TDFXMakeRoom(pTDFX, 2);
|
|
DECLARE(SSTCP_SRCFORMAT|SSTCP_DSTFORMAT);
|
|
TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, pTDFX->sst2DDstFmtShadow);
|
|
TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, pTDFX->sst2DSrcFmtShadow);
|
|
|
|
/* Wait for it to happen */
|
|
TDFXSendNOPFifo2D(pScrn);
|
|
|
|
return Success;
|
|
}
|
|
|
|
|
|
/*
|
|
* OVERLAY DRAWING FUNCTIONS
|
|
*/
|
|
|
|
|
|
static void
|
|
TDFXResetVideoOverlay(ScrnInfoPtr pScrn)
|
|
{
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
TDFXPortPrivPtr pPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr;
|
|
|
|
/* reset the video */
|
|
pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
|
|
pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
|
|
pTDFX->writeLong(pTDFX, RGBMAXDELTA, 0x0080808);
|
|
pTDFX->writeLong(pTDFX, VIDCHROMAMIN, pPriv->colorKey);
|
|
pTDFX->writeLong(pTDFX, VIDCHROMAMAX, pPriv->colorKey);
|
|
}
|
|
|
|
|
|
static void
|
|
TDFXStopVideoOverlay(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
|
|
{
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data;
|
|
|
|
REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
|
|
|
|
if(cleanup) {
|
|
if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
|
|
pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
|
|
pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
|
|
}
|
|
if(pTDFX->overlayBuffer) {
|
|
xf86FreeOffscreenLinear(pTDFX->overlayBuffer);
|
|
pTDFX->overlayBuffer = NULL;
|
|
}
|
|
if(pTDFX->overlayBuffer2) {
|
|
xf86FreeOffscreenLinear(pTDFX->overlayBuffer2);
|
|
pTDFX->overlayBuffer2 = NULL;
|
|
}
|
|
pPriv->videoStatus = 0;
|
|
} else {
|
|
if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
|
|
pPriv->videoStatus |= OFF_TIMER;
|
|
pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* * * * * *
|
|
|
|
Decoder...
|
|
|
|
VIDPROCCFG: 0x5c: Video Processor Configuration register
|
|
|
|
#define VIDPROCCFGMASK 0xa2e3eb6c
|
|
3 2 1 0
|
|
10987654321098765432109876543210
|
|
10100010111000111110101101101100
|
|
|
|
The "1" bits are the bits cleared to 0 in pTDFX->ModeReg.vidcfg
|
|
|
|
|
|
Then we or in 0x320:
|
|
|
|
11
|
|
109876543210
|
|
320 = 001100100000
|
|
|
|
bit 11=0: Do not bypass clut (colour lookup) for overlay
|
|
bit 10=0: Do not bypass clut for desktop
|
|
bit 9=1: use video-in buffer address as overlay start
|
|
address (auto-flipping)
|
|
bit 8=1: fetch overlay surface
|
|
bit 7=0: do not fetch the desktop surface (?)
|
|
bit 6=0: chromakey not inverted
|
|
bit 5=1: chromakey enabled
|
|
bit 4=0: half-mode disabled
|
|
bit 3=0: not interlaced (interlace doesn't work on Avenger)
|
|
bit 2=0: overlay stereo disabled
|
|
bit 1=0: Windows cursor mode
|
|
bit 0=0: Video processor off, VGA mode on
|
|
|
|
SST_VIDEO_2X_MODE_EN: bit26: means 2 pixels per screen clock mode is on
|
|
|
|
VIDOVERLAYSTARTCOORDS: x&y coords of overlay on the screen
|
|
VIDOVERLAYENDSCREENCOORDS: x&y coorder of bot-right of overlay on the screen
|
|
VIDOVERLAYDUDX: step size in source per hoz step in screen space (x-mag)
|
|
VIDOVERLAYDUDXOFFSETSRCWIDTH:
|
|
VIDOVERLAYDVDY: step size in sourcxe per vertical step in screen (y-mag)
|
|
VIDOVERLAYDVDYOFFSET: initial offset of DVDY
|
|
VIDDESKTOPOVERLAYSTRIDE: desktop surface stride
|
|
|
|
SST_3D_LEFTOVERLAYBUF: starting physical address of the overlay surface buffer
|
|
VIDINADDR0: starting address of video-in buffer-0
|
|
[this is set, but this is for video _input_ as I understand docs...?]
|
|
|
|
* * * * * */
|
|
|
|
static void
|
|
TDFXDisplayVideoOverlay(
|
|
ScrnInfoPtr pScrn,
|
|
int id,
|
|
int offset,
|
|
short width, short height,
|
|
int pitch,
|
|
int left, int right, int top,
|
|
BoxPtr dstBox,
|
|
short src_w, short src_h,
|
|
short drw_w, short drw_h
|
|
){
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
TDFXPortPrivPtr pPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr;
|
|
int dudx, dvdy;
|
|
|
|
dudx = (src_w << 20) / drw_w;
|
|
/* subtract 1 to eliminate garbage on last line */
|
|
dvdy = (( src_h - 1 )<< 20) / drw_h;
|
|
|
|
offset += ((left >> 16) & ~1) << 1;
|
|
left = (left & 0x0001ffff) << 3;
|
|
|
|
pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
|
|
pTDFX->ModeReg.vidcfg |= 0x00000320;
|
|
|
|
if(drw_w != src_w) pTDFX->ModeReg.vidcfg |= (1 << 14);
|
|
if(drw_h != src_h) pTDFX->ModeReg.vidcfg |= (1 << 15);
|
|
if(id == FOURCC_UYVY) pTDFX->ModeReg.vidcfg |= (6 << 21);
|
|
else pTDFX->ModeReg.vidcfg |= (5 << 21);
|
|
if(pScrn->depth == 8) pTDFX->ModeReg.vidcfg |= (1 << 11);
|
|
/* can't do bilinear filtering when in 2X mode */
|
|
if(pPriv->filterQuality && !(pTDFX->ModeReg.vidcfg & SST_VIDEO_2X_MODE_EN))
|
|
pTDFX->ModeReg.vidcfg |= (3 << 16);
|
|
pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
|
|
|
|
pTDFX->writeLong(pTDFX, VIDOVERLAYSTARTCOORDS, dstBox->x1 | (dstBox->y1 << 12));
|
|
pTDFX->writeLong(pTDFX, VIDOVERLAYENDSCREENCOORDS, (dstBox->x2 - 1) | ((dstBox->y2 - 1) << 12));
|
|
pTDFX->writeLong(pTDFX, VIDOVERLAYDUDX, dudx);
|
|
pTDFX->writeLong(pTDFX, VIDOVERLAYDUDXOFFSETSRCWIDTH, left | (src_w << 20));
|
|
pTDFX->writeLong(pTDFX, VIDOVERLAYDVDY, dvdy);
|
|
pTDFX->writeLong(pTDFX, VIDOVERLAYDVDYOFFSET, (top & 0x0000ffff) << 3);
|
|
|
|
pTDFX->ModeReg.stride &= 0x0000ffff;
|
|
pTDFX->ModeReg.stride |= pitch << 16;
|
|
pTDFX->writeLong(pTDFX, VIDDESKTOPOVERLAYSTRIDE, pTDFX->ModeReg.stride);
|
|
pTDFX->writeLong(pTDFX, SST_3D_LEFTOVERLAYBUF, offset & ~3);
|
|
pTDFX->writeLong(pTDFX, VIDINADDR0, offset & ~3);
|
|
TDFXTRACE("TDFXDisplayVideoOverlay: done, offset=0x%x\n", offset);
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
/* * * * *
|
|
|
|
TDFXSwapVideoOverlayBuffer tries to use the Avenger SWAPBUFFER
|
|
capability to change frames without tearing.
|
|
|
|
Use this in preference to TDFXDisplayVideoOverlay where all image
|
|
parameters are the same as the previous frame - ie where only the
|
|
SST_3D_LEFTOVERLAYBUF register would have been changed.
|
|
|
|
NOTE: Work in progress - doesn't seem to sync to VSYNC, and only every
|
|
other frame gets displayed...
|
|
|
|
Seeing that the buffer swap initiated by DisplayVideoOverlay gets
|
|
synced to VSYNC anyway, just adding double-buffering to PutImageOverlay
|
|
appears to do the job. Still - I leave this code in in case we can
|
|
get it working later
|
|
|
|
-- Steve Davies 2002-10-04
|
|
-- <steve@daviesfam.org>
|
|
|
|
* * * * * */
|
|
|
|
static void
|
|
TDFXSwapVideoOverlayBuffer(
|
|
ScrnInfoPtr pScrn,
|
|
int offset,
|
|
int left
|
|
){
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
offset += ((left >> 16) & ~1) << 1;
|
|
/* Write mew buffer address */
|
|
pTDFX->writeLong(pTDFX, SST_3D_LEFTOVERLAYBUF, offset & ~3);
|
|
/* Incremement the swap-pending counter */
|
|
pTDFX->writeLong(pTDFX, SST_3D_SWAPPENDING, 0);
|
|
/* write the swapbuffer command - triggered by (next) VSYNC */
|
|
pTDFX->writeLong(pTDFX, SST_3D_SWAPBUFFERCMD, 1);
|
|
}
|
|
|
|
#endif
|
|
|
|
static int
|
|
TDFXPutImageOverlay(
|
|
ScrnInfoPtr pScrn,
|
|
short src_x, short src_y,
|
|
short drw_x, short drw_y,
|
|
short src_w, short src_h,
|
|
short drw_w, short drw_h,
|
|
int id, unsigned char* buf,
|
|
short width, short height,
|
|
Bool Sync,
|
|
RegionPtr clipBoxes, pointer data,
|
|
DrawablePtr pDraw
|
|
){
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data;
|
|
INT32 xa, xb, ya, yb;
|
|
unsigned char *dst_start;
|
|
int new_size, offset;
|
|
int s2offset = 0, s3offset = 0;
|
|
int srcPitch = 0, srcPitch2 = 0;
|
|
int dstPitch;
|
|
int top, left, npixels, nlines, bpp;
|
|
BoxRec dstBox;
|
|
CARD32 tmp;
|
|
|
|
TDFXTRACE("TDFXPutImageOverlay: src_x=%d, src_y=%d, drw_x=%d, drw_y=%d, src_w=%d, src_h=%d, drw_w=%d, drw_h=%d, id=%d, width=%d, height=%d, sync=%d\n",
|
|
src_x, src_y, drw_x, drw_y, src_w, src_h, drw_w, drw_h, id, width, height, Sync);
|
|
|
|
/*
|
|
* s2offset, s3offset - byte offsets into U and V plane of the
|
|
* source where copying starts. Y plane is
|
|
* done by editing "buf".
|
|
*
|
|
* offset - byte offset to the first line of the destination.
|
|
*
|
|
* dst_start - byte address to the first displayed pel.
|
|
*
|
|
*/
|
|
|
|
if(src_w > drw_w) drw_w = src_w;
|
|
if(src_h > drw_h) drw_h = src_h;
|
|
|
|
/* Clip */
|
|
xa = src_x;
|
|
xb = src_x + src_w;
|
|
ya = src_y;
|
|
yb = src_y + src_h;
|
|
|
|
dstBox.x1 = drw_x;
|
|
dstBox.x2 = drw_x + drw_w;
|
|
dstBox.y1 = drw_y;
|
|
dstBox.y2 = drw_y + drw_h;
|
|
|
|
if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb,
|
|
clipBoxes, width, height))
|
|
return Success;
|
|
|
|
dstBox.x1 -= pScrn->frameX0;
|
|
dstBox.x2 -= pScrn->frameX0;
|
|
dstBox.y1 -= pScrn->frameY0;
|
|
dstBox.y2 -= pScrn->frameY0;
|
|
|
|
bpp = pScrn->bitsPerPixel >> 3;
|
|
|
|
switch(id) {
|
|
case FOURCC_YV12:
|
|
case FOURCC_I420:
|
|
dstPitch = ((width << 1) + 3) & ~3;
|
|
new_size = ((dstPitch * height) + bpp - 1) / bpp;
|
|
srcPitch = (width + 3) & ~3;
|
|
s2offset = srcPitch * height;
|
|
srcPitch2 = ((width >> 1) + 3) & ~3;
|
|
s3offset = (srcPitch2 * (height >> 1)) + s2offset;
|
|
break;
|
|
case FOURCC_UYVY:
|
|
case FOURCC_YUY2:
|
|
default:
|
|
dstPitch = ((width << 1) + 3) & ~3;
|
|
new_size = ((dstPitch * height) + bpp - 1) / bpp;
|
|
srcPitch = (width << 1);
|
|
break;
|
|
}
|
|
|
|
if(!(pTDFX->overlayBuffer = TDFXAllocateMemoryLinear(pScrn, pTDFX->overlayBuffer, new_size)))
|
|
return BadAlloc;
|
|
/* Second buffer for double-buffering (If we can't get the memory then we just don't double-buffer) */
|
|
if (!(pTDFX->overlayBuffer2 = TDFXAllocateMemoryLinear(pScrn, pTDFX->overlayBuffer2, new_size)))
|
|
pTDFX->whichOverlayBuffer = 0;
|
|
TDFXTRACE("TDFXPutImageOverlay: %s have a second overlay buffer for double-buffering\n",
|
|
pTDFX->overlayBuffer2 ? "Do" : "Do not");
|
|
|
|
/* copy data */
|
|
top = ya >> 16;
|
|
left = (xa >> 16) & ~1;
|
|
npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left;
|
|
|
|
/* Get buffer offset */
|
|
if (pTDFX->whichOverlayBuffer == 0)
|
|
offset = (pTDFX->overlayBuffer->offset * bpp) + (top * dstPitch) + pTDFX->fbOffset;
|
|
else
|
|
offset = (pTDFX->overlayBuffer2->offset * bpp) + (top * dstPitch) + pTDFX->fbOffset;
|
|
|
|
/* Flip to other buffer for next time */
|
|
pTDFX->whichOverlayBuffer ^= 1;
|
|
|
|
dst_start = pTDFX->FbBase + 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;
|
|
TDFXTRACE("TDFXPutImageOverlay: using copymungeddata\n");
|
|
TDFXCopyMungedData(buf + (top * srcPitch) + left, buf + s2offset,
|
|
buf + s3offset, dst_start, srcPitch, srcPitch2,
|
|
dstPitch, nlines, npixels);
|
|
break;
|
|
case FOURCC_UYVY:
|
|
case FOURCC_YUY2:
|
|
default:
|
|
left <<= 1;
|
|
buf += (top * srcPitch) + left;
|
|
nlines = ((yb + 0xffff) >> 16) - top;
|
|
dst_start += left;
|
|
TDFXTRACE("TDFXPutImageOverlay: using copydata\n");
|
|
TDFXCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
|
|
break;
|
|
}
|
|
|
|
if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
|
|
REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
|
|
xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
|
|
}
|
|
|
|
TDFXDisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch, xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
|
|
|
|
pPriv->videoStatus = CLIENT_VIDEO_ON;
|
|
|
|
pTDFX->VideoTimerCallback = TDFXVideoTimerCallback;
|
|
|
|
/* Display some swap-buffer related info...: vidCurrOverlayStartAddr, fbiSwapHistory */
|
|
/* To give us some insight into workings or otherwise of swapbuffer stuff */
|
|
TDFXTRACE("TDFXPutImageOverlay: vidCurrOverlayStrtAdr=%x, fbiSwpHist=%x, whchBuf=%d, 3Dstus=%x\n",
|
|
pTDFX->readLong(pTDFX, VIDCUROVERLAYSTARTADDR),
|
|
pTDFX->readLong(pTDFX, SST_3D_FBISWAPHISTORY),
|
|
pTDFX->whichOverlayBuffer,
|
|
pTDFX->readLong(pTDFX, SST_3D_STATUS)
|
|
);
|
|
|
|
return Success;
|
|
}
|
|
|
|
|
|
static void
|
|
TDFXVideoTimerCallback(ScrnInfoPtr pScrn, Time time)
|
|
{
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
TDFXPortPrivPtr pPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr;
|
|
|
|
if(pPriv->videoStatus & TIMER_MASK) {
|
|
if(pPriv->videoStatus & OFF_TIMER) {
|
|
if(pPriv->offTime < time) {
|
|
pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
|
|
pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
|
|
pPriv->videoStatus = FREE_TIMER;
|
|
pPriv->freeTime = time + FREE_DELAY;
|
|
}
|
|
} else
|
|
if(pPriv->videoStatus & FREE_TIMER) {
|
|
if(pPriv->freeTime < time) {
|
|
if(pTDFX->overlayBuffer) {
|
|
xf86FreeOffscreenLinear(pTDFX->overlayBuffer);
|
|
pTDFX->overlayBuffer = NULL;
|
|
}
|
|
if(pTDFX->overlayBuffer2) {
|
|
xf86FreeOffscreenLinear(pTDFX->overlayBuffer2);
|
|
pTDFX->overlayBuffer2 = NULL;
|
|
}
|
|
pPriv->videoStatus = 0;
|
|
pTDFX->VideoTimerCallback = NULL;
|
|
}
|
|
}
|
|
} else /* shouldn't get here */
|
|
pTDFX->VideoTimerCallback = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* MEMORY MANAGEMENT
|
|
*/
|
|
|
|
|
|
static FBAreaPtr
|
|
TDFXAllocateMemoryArea (ScrnInfoPtr pScrn, FBAreaPtr area, int width, int height)
|
|
{
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
ScreenPtr pScreen;
|
|
FBAreaPtr new_area;
|
|
|
|
if (area) {
|
|
if ((area->box.x2 - area->box.x1 >= width) &&
|
|
(area->box.y2 - area->box.y1 >= height))
|
|
return area;
|
|
|
|
if (xf86ResizeOffscreenArea(area, width, height))
|
|
return area;
|
|
|
|
xf86FreeOffscreenArea(area);
|
|
}
|
|
|
|
pScreen = xf86ScrnToScreen(pScrn);
|
|
|
|
new_area = xf86AllocateOffscreenArea(pScreen, width, height, pTDFX->cpp, NULL, NULL, NULL);
|
|
|
|
if (!new_area) {
|
|
int max_width, max_height;
|
|
|
|
xf86QueryLargestOffscreenArea(pScreen, &max_width, &max_height, pTDFX->cpp, 0, PRIORITY_EXTREME);
|
|
|
|
if (max_width < width || max_height < height)
|
|
return NULL;
|
|
|
|
xf86PurgeUnlockedOffscreenAreas(pScreen);
|
|
new_area = xf86AllocateOffscreenArea(pScreen, width, height, pTDFX->cpp, NULL, NULL, NULL);
|
|
}
|
|
|
|
return new_area;
|
|
}
|
|
|
|
|
|
static FBLinearPtr
|
|
TDFXAllocateMemoryLinear (ScrnInfoPtr pScrn, FBLinearPtr linear, int size)
|
|
{
|
|
ScreenPtr pScreen;
|
|
FBLinearPtr new_linear;
|
|
|
|
if(linear) {
|
|
if(linear->size >= size)
|
|
return linear;
|
|
|
|
if(xf86ResizeOffscreenLinear(linear, size))
|
|
return linear;
|
|
|
|
xf86FreeOffscreenLinear(linear);
|
|
}
|
|
|
|
pScreen = xf86ScrnToScreen(pScrn);
|
|
|
|
new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, NULL, NULL, NULL);
|
|
|
|
if(!new_linear) {
|
|
int max_size;
|
|
|
|
xf86QueryLargestOffscreenLinear(pScreen, &max_size, 4, PRIORITY_EXTREME);
|
|
|
|
if(max_size < size)
|
|
return NULL;
|
|
|
|
xf86PurgeUnlockedOffscreenAreas(pScreen);
|
|
new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, NULL, NULL, NULL);
|
|
}
|
|
|
|
return new_linear;
|
|
}
|
|
|
|
/****************** Offscreen stuff ***************/
|
|
|
|
typedef struct {
|
|
FBLinearPtr linear;
|
|
Bool isOn;
|
|
} OffscreenPrivRec, * OffscreenPrivPtr;
|
|
|
|
static int
|
|
TDFXAllocateSurface(
|
|
ScrnInfoPtr pScrn,
|
|
int id,
|
|
unsigned short w,
|
|
unsigned short h,
|
|
XF86SurfacePtr surface
|
|
){
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
FBLinearPtr linear;
|
|
int pitch, size, bpp;
|
|
OffscreenPrivPtr pPriv;
|
|
|
|
if((w > 2048) || (h > 2048))
|
|
return BadAlloc;
|
|
|
|
w = (w + 1) & ~1;
|
|
pitch = ((w << 1) + 15) & ~15;
|
|
bpp = pScrn->bitsPerPixel >> 3;
|
|
size = ((pitch * h) + bpp - 1) / bpp;
|
|
|
|
if(!(linear = TDFXAllocateMemoryLinear(pScrn, NULL, size)))
|
|
return BadAlloc;
|
|
|
|
surface->width = w;
|
|
surface->height = h;
|
|
|
|
if(!(surface->pitches = malloc(sizeof(int)))) {
|
|
xf86FreeOffscreenLinear(linear);
|
|
return BadAlloc;
|
|
}
|
|
if(!(surface->offsets = malloc(sizeof(int)))) {
|
|
free(surface->pitches);
|
|
xf86FreeOffscreenLinear(linear);
|
|
return BadAlloc;
|
|
}
|
|
if(!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
|
|
free(surface->pitches);
|
|
free(surface->offsets);
|
|
xf86FreeOffscreenLinear(linear);
|
|
return BadAlloc;
|
|
}
|
|
|
|
pPriv->linear = linear;
|
|
pPriv->isOn = FALSE;
|
|
|
|
surface->pScrn = pScrn;
|
|
surface->id = id;
|
|
surface->pitches[0] = pitch;
|
|
surface->offsets[0] = pTDFX->fbOffset + (linear->offset * bpp);
|
|
surface->devPrivate.ptr = (pointer)pPriv;
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
TDFXStopSurface(
|
|
XF86SurfacePtr surface
|
|
){
|
|
OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
|
|
|
|
if(pPriv->isOn) {
|
|
TDFXPtr pTDFX = TDFXPTR(surface->pScrn);
|
|
pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
|
|
pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
|
|
pPriv->isOn = FALSE;
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
|
|
static int
|
|
TDFXFreeSurface(
|
|
XF86SurfacePtr surface
|
|
){
|
|
OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
|
|
|
|
if(pPriv->isOn)
|
|
TDFXStopSurface(surface);
|
|
xf86FreeOffscreenLinear(pPriv->linear);
|
|
free(surface->pitches);
|
|
free(surface->offsets);
|
|
free(surface->devPrivate.ptr);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
TDFXGetSurfaceAttribute(
|
|
ScrnInfoPtr pScrn,
|
|
Atom attribute,
|
|
INT32 *value
|
|
){
|
|
return TDFXGetPortAttributeOverlay(pScrn, attribute, value,
|
|
(pointer)(GET_PORT_PRIVATE(pScrn)));
|
|
}
|
|
|
|
static int
|
|
TDFXSetSurfaceAttribute(
|
|
ScrnInfoPtr pScrn,
|
|
Atom attribute,
|
|
INT32 value
|
|
){
|
|
return TDFXSetPortAttributeOverlay(pScrn, attribute, value,
|
|
(pointer)(GET_PORT_PRIVATE(pScrn)));
|
|
}
|
|
|
|
static int
|
|
TDFXDisplaySurface(
|
|
XF86SurfacePtr surface,
|
|
short src_x, short src_y,
|
|
short drw_x, short drw_y,
|
|
short src_w, short src_h,
|
|
short drw_w, short drw_h,
|
|
RegionPtr clipBoxes
|
|
){
|
|
OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
|
|
ScrnInfoPtr pScrn = surface->pScrn;
|
|
TDFXPtr pTDFX = TDFXPTR(pScrn);
|
|
TDFXPortPrivPtr portPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr;
|
|
INT32 x1, y1, x2, y2;
|
|
BoxRec dstBox;
|
|
|
|
x1 = src_x;
|
|
x2 = src_x + src_w;
|
|
y1 = src_y;
|
|
y2 = src_y + src_h;
|
|
|
|
dstBox.x1 = drw_x;
|
|
dstBox.x2 = drw_x + drw_w;
|
|
dstBox.y1 = drw_y;
|
|
dstBox.y2 = drw_y + drw_h;
|
|
|
|
if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
|
|
surface->width, surface->height))
|
|
{
|
|
return Success;
|
|
}
|
|
|
|
dstBox.x1 -= pScrn->frameX0;
|
|
dstBox.x2 -= pScrn->frameX0;
|
|
dstBox.y1 -= pScrn->frameY0;
|
|
dstBox.y2 -= pScrn->frameY0;
|
|
|
|
#if 0
|
|
TDFXResetVideoOverlay(pScrn);
|
|
#endif
|
|
|
|
TDFXDisplayVideoOverlay(pScrn, surface->id, surface->offsets[0],
|
|
surface->width, surface->height, surface->pitches[0],
|
|
x1, y1, x2, &dstBox, src_w, src_h, drw_w, drw_h);
|
|
|
|
xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);
|
|
|
|
pPriv->isOn = TRUE;
|
|
/* we've prempted the XvImage stream so set its free timer */
|
|
if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
|
|
REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
|
|
UpdateCurrentTime();
|
|
portPriv->videoStatus = FREE_TIMER;
|
|
portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
|
|
pTDFX->VideoTimerCallback = TDFXVideoTimerCallback;
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
static void
|
|
TDFXInitOffscreenImages(ScreenPtr pScreen)
|
|
{
|
|
XF86OffscreenImagePtr offscreenImages;
|
|
|
|
/* need to free this someplace */
|
|
if(!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
|
|
return;
|
|
|
|
offscreenImages[0].image = &OverlayImages[0];
|
|
offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
|
|
VIDEO_CLIP_TO_VIEWPORT;
|
|
offscreenImages[0].alloc_surface = TDFXAllocateSurface;
|
|
offscreenImages[0].free_surface = TDFXFreeSurface;
|
|
offscreenImages[0].display = TDFXDisplaySurface;
|
|
offscreenImages[0].stop = TDFXStopSurface;
|
|
offscreenImages[0].setAttribute = TDFXSetSurfaceAttribute;
|
|
offscreenImages[0].getAttribute = TDFXGetSurfaceAttribute;
|
|
offscreenImages[0].max_width = 2048;
|
|
offscreenImages[0].max_height = 2048;
|
|
offscreenImages[0].num_attributes = 2;
|
|
offscreenImages[0].attributes = OverlayAttributes;
|
|
|
|
xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
|
|
}
|