
#ifdef RENDER

#ifdef ACCEL_CP

#include "mipict.h"
#include "dixstruct.h"
#include "xaalocal.h"

CARD32 RADEONAlphaTextureFormats[2] = {PICT_a8, 0};
CARD32 RADEONTextureFormats[2] = {PICT_a8r8g8b8, 0};

static void
RemoveLinear (FBLinearPtr linear)
{
    RADEONInfoPtr info = (RADEONInfoPtr)(linear->devPrivate.ptr);

    info->LinearScratch = NULL;  /* just lost our scratch */
}

static void
RenderCallback (ScrnInfoPtr pScrn)
{
    RADEONInfoPtr info = RADEONPTR(pScrn);

    if((currentTime.milliseconds > info->RenderTime) && info->LinearScratch) {
	xf86FreeOffscreenLinear(info->LinearScratch);
	info->LinearScratch = NULL;
    }

    if(!info->LinearScratch)
	info->RenderCallback = NULL;
}

#define RENDER_DELAY	15000

static Bool
AllocateLinear (
    ScrnInfoPtr pScrn,
    int sizeNeeded
){
    RADEONInfoPtr info = RADEONPTR(pScrn);

    info->RenderTime = currentTime.milliseconds + RENDER_DELAY;
    info->RenderCallback = RenderCallback;

    if(info->LinearScratch) {
	if(info->LinearScratch->size >= sizeNeeded)
	    return TRUE;
	else {
	    if(xf86ResizeOffscreenLinear(info->LinearScratch, sizeNeeded))
	        return TRUE;

	    xf86FreeOffscreenLinear(info->LinearScratch);
	    info->LinearScratch = NULL;
	}
    }

    info->LinearScratch = xf86AllocateOffscreenLinear( pScrn->pScreen, sizeNeeded,
						       32, NULL, RemoveLinear, info);

   return (info->LinearScratch != NULL);
}

static void UploadCommon3DState(ScrnInfoPtr pScrn)
{
    RADEONInfoPtr info = RADEONPTR(pScrn);
    RING_LOCALS;

    if ( 1 || RADEON_VERBOSE )
        xf86DrvMsg( pScrn->scrnIndex, X_INFO, "%s enter\n", __FUNCTION__ );

    RADEONCP_REFRESH( pScrn, info );

    BEGIN_RING( 30 );

    OUT_RING_REG_FLOAT( RADEON_SE_VPORT_XSCALE, 1.0 );
    OUT_RING_REG_FLOAT( RADEON_SE_VPORT_YSCALE, 1.0 );
    OUT_RING_REG_FLOAT( RADEON_SE_VPORT_XOFFSET, 0.0 );
    OUT_RING_REG_FLOAT( RADEON_SE_VPORT_YOFFSET, 0.0 );
    OUT_RING_REG( RADEON_PP_MISC, RADEON_ALPHA_TEST_PASS );
    OUT_RING_REG( RADEON_RE_SOLID_COLOR, 0xffffffff );
    OUT_RING_REG( RADEON_RB3D_BLENDCNTL, RADEON_SRC_BLEND_GL_SRC_ALPHA
				       | RADEON_DST_BLEND_GL_ONE );
    OUT_RING_REG( RADEON_PP_CNTL, RADEON_TEX_0_ENABLE );
    OUT_RING_REG( RADEON_RB3D_CNTL, RADEON_ALPHA_BLEND_ENABLE
				  | (pScrn->bitsPerPixel == 32
				     ? RADEON_COLOR_FORMAT_ARGB8888
				     : RADEON_COLOR_FORMAT_ARGB1555) );
    OUT_RING_REG( RADEON_RB3D_COLOROFFSET, 0x0 );
    OUT_RING_REG( RADEON_RE_TOP_LEFT, 0 );
    OUT_RING_REG( RADEON_RE_WIDTH_HEIGHT, (pScrn->virtualX-1) | ((pScrn->virtualY-1) << RADEON_RE_HEIGHT_SHIFT) );
    OUT_RING_REG( RADEON_RB3D_COLORPITCH, pScrn->displayWidth /*/8*/ );
    OUT_RING_REG( RADEON_SE_CNTL, RADEON_BFACE_SOLID | RADEON_FFACE_SOLID
				| RADEON_VTX_PIX_CENTER_OGL );
    OUT_RING_REG( RADEON_PP_TXFILTER_0, RADEON_MAG_FILTER_NEAREST
				      | RADEON_MIN_FILTER_NEAREST );

    info->StateUploaded = TRUE;

    if ( 1 || RADEON_VERBOSE )
        xf86DrvMsg( pScrn->scrnIndex, X_INFO, "%s exit\n", __FUNCTION__ );
}

static Bool
FUNC_NAME(SetupForCPUToScreenAlphaTexture) (
   ScrnInfoPtr	pScrn,
   int		op,
   CARD16	red,
   CARD16	green,
   CARD16	blue,
   CARD16	alpha,
   int		alphaType,
   CARD8	*alphaPtr,
   int		alphaPitch,
   int		width,
   int		height,
   int		flags
){
    int sizeNeeded, offset, pitch;
    RADEONInfoPtr info = RADEONPTR(pScrn);
    RING_LOCALS;

    if ( 1 || RADEON_VERBOSE )
        xf86DrvMsg( pScrn->scrnIndex, X_INFO, "%s enter\n", __FUNCTION__ );

    RADEONCP_REFRESH( pScrn, info );

    BEGIN_RING( 30 );

    if (op != PictOpOver)  /* only one tested */
	return FALSE;

    if ((width > 2048) || (height > 2048))
	return FALSE;

    pitch = max(width*4, 32);
    sizeNeeded = (pitch * height) >> (pScrn->bitsPerPixel >> 4);

    if(!AllocateLinear(pScrn, sizeNeeded))
	return FALSE;

    offset = info->LinearScratch->offset << (pScrn->bitsPerPixel >> 4);

    if(info->accel->NeedToSync)
	  info->accel->Sync(pScrn);

    XAA_888_plus_PICT_a8_to_8888(
	(blue >> 8) | (green & 0xff00) | ((red & 0xff00) << 8),
	alphaPtr, alphaPitch, (CARD32*)(info->FB + offset),
        pitch, width, height);

    if (!info->StateUploaded)
	UploadCommon3DState(pScrn);

    RADEONCP_REFRESH( pScrn, info );

    BEGIN_RING( 8 );

    OUT_RING_REG( RADEON_PP_TXFORMAT_0, RADEON_TXFORMAT_RGBA8888
				      | RADEON_TXFORMAT_ALPHA_IN_MAP
				      | RADEON_TXFORMAT_NON_POWER2
				      | RADEON_TXFORMAT_ALPHA_MASK_ENABLE );
    OUT_RING_REG( RADEON_PP_TXOFFSET_0, offset );
    OUT_RING_REG( RADEON_PP_TXPITCH_0, pitch - 32 );
    OUT_RING_REG( RADEON_PP_TXSIZE_0, (width-1) | ((height-1) << 16) );

    ADVANCE_RING();

    if ( 1 || RADEON_VERBOSE )
        xf86DrvMsg( pScrn->scrnIndex, X_INFO, "%s exit\n", __FUNCTION__ );

    return TRUE;
}

static Bool
FUNC_NAME(SetupForCPUToScreenTexture) (
   ScrnInfoPtr	pScrn,
   int		op,
   int		texType,
   CARD8	*texPtr,
   int		texPitch,
   int		width,
   int		height,
   int		flags
){
    int i, sizeNeeded, pitch, offset;
    RADEONInfoPtr info = RADEONPTR(pScrn);
    RING_LOCALS;

    if ( 1 || RADEON_VERBOSE )
        xf86DrvMsg( pScrn->scrnIndex, X_INFO, "%s enter\n", __FUNCTION__ );

    if (op != PictOpOver)  /* only one tested */
	return FALSE;

    if ((width > 2048) || (height > 2048))
	return FALSE;

    pitch = max(width*4, 32);
    sizeNeeded = pitch * height;
    if (pScrn->bitsPerPixel == 16)
	sizeNeeded <<= 1;

    if (!AllocateLinear(pScrn, sizeNeeded))
	return FALSE;

    offset = info->LinearScratch->offset << 1;
    if (pScrn->bitsPerPixel == 32)
        offset <<= 1;

    if (info->accel->NeedToSync)
	  info->accel->Sync(pScrn);

    {
	CARD8 *dst = (CARD8*)(info->FB + offset);

	i = height;
	while(i--) {
	    memcpy(dst, texPtr, width << 2);
	    texPtr += texPitch;
	    dst += pitch << 2;
	}
    }

    if (!info->StateUploaded)
	UploadCommon3DState(pScrn);

    RADEONCP_REFRESH( pScrn, info );

    BEGIN_RING( 8 );

    OUT_RING_REG( RADEON_PP_TXFORMAT_0, RADEON_TXFORMAT_RGBA8888
				      | RADEON_TXFORMAT_ALPHA_IN_MAP
				      | RADEON_TXFORMAT_NON_POWER2
				      | RADEON_TXFORMAT_ALPHA_MASK_ENABLE );
    OUT_RING_REG( RADEON_PP_TXOFFSET_0, offset );
    OUT_RING_REG( RADEON_PP_TXPITCH_0, pitch - 32 );
    OUT_RING_REG( RADEON_PP_TXSIZE_0, (width-1) | ((height-1) << 16) );

    ADVANCE_RING();

    if ( RADEON_VERBOSE )
        xf86DrvMsg( pScrn->scrnIndex, X_INFO, "%s exit\n", __FUNCTION__ );

    return TRUE;
}

static void
FUNC_NAME(SubsequentCPUToScreenTexture) (
    ScrnInfoPtr	pScrn,
    int		dstx,
    int		dsty,
    int		srcx,
    int		srcy,
    int		width,
    int		height
){
    RADEONInfoPtr info = RADEONPTR(pScrn);
    RING_LOCALS;

    if ( 1 || RADEON_VERBOSE )
        xf86DrvMsg( pScrn->scrnIndex, X_INFO, "%s enter\n", __FUNCTION__ );

    RADEONCP_REFRESH( pScrn, info );

    BEGIN_RING( 27 );

    OUT_RING( CP_PACKET3( RADEON_CP_PACKET3_3D_DRAW_IMMD, 25) );
    OUT_RING( RADEON_TCL_VTX_ST0 );
    OUT_RING( RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST | RADEON_CP_VC_CNTL_PRIM_WALK_RING
	    | RADEON_CP_VC_CNTL_MAOS_ENABLE | RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE
	    | (6 << RADEON_CP_VC_CNTL_NUM_SHIFT) );

    /* upper left triangle */
    OUT_RING( dstx );		OUT_RING( dsty );
    OUT_RING( srcx );		OUT_RING( srcy );
    OUT_RING( dstx+width );	OUT_RING( dsty );
    OUT_RING( srcx+width );	OUT_RING( srcy );
    OUT_RING( dstx );		OUT_RING( dsty+height );
    OUT_RING( srcx );		OUT_RING( srcy+height );

    /* lower right triangle */
    OUT_RING( dstx );		OUT_RING( dsty+height );
    OUT_RING( srcx );		OUT_RING( srcy+height );
    OUT_RING( dstx+width );	OUT_RING( dsty );
    OUT_RING( srcx+width );	OUT_RING( srcy );
    OUT_RING( dstx+width );	OUT_RING( dsty+height );
    OUT_RING( srcx+width );	OUT_RING( srcy+height );

    ADVANCE_RING();

    SET_SYNC_FLAG(info->accel);

    if ( 1 || RADEON_VERBOSE )
        xf86DrvMsg( pScrn->scrnIndex, X_INFO, "%s exit\n", __FUNCTION__ );
}

#endif	/* ACCEL_CP */

#endif	/* RENDER */

