//
// Copyright (c) Samsung Electronics. Co. LTD.  All rights reserved.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:    FIMG2D.cpp
Abstract:       hardware control implementation for FIMG-2D v3.0, This class is a kind of adapter
Functions:
Notes:          This version is made for FIMG2D v3.0
--*/

#include "precomp.h"
#include <assert.h>
#include <dispperf.h>
#include "g2d_def_v3.h"
#include <DrvLib_mem.h>


extern "C"
{
    void InvalidateDCacheForG2D(VOID* pAddress, DWORD width, DWORD height, DWORD stride);
    void CleanDCacheForG2D(VOID *pAddress, DWORD width, DWORD height, DWORD stride);
    void CleanAndInvalidateDCacheForG2D(VOID* pAddress, DWORD width, DWORD height, DWORD stride);
}


FIMG2D::FIMG2D()
{
    PHYSICAL_ADDRESS    ioPhysicalAddress;
    ioPhysicalAddress.LowPart = BASE_REG_PA_G2D;
    m_pG2DReg = (G2D_REG *)MmMapIoSpace(ioPhysicalAddress, sizeof(G2D_REG), FALSE);
    if (m_pG2DReg == NULL)
    {
        RETAIL_2D_MSG(DISP_ZONE_ERROR, (_T("[G2D] RegCtrlG2D() : m_pG2DReg MmMapIoSpace() Failed \n\r")));
    }
    InitClk();   
}


FIMG2D::~FIMG2D()
{
    if (m_pG2DReg != NULL)
    {
        MmUnmapIoSpace((PVOID)m_pG2DReg, sizeof(G2D_REG));
        m_pG2DReg = NULL;
    }
}


void
FIMG2D::InitClk()
{
    DWORD dwTimeOut = 0;
    volatile DWORD dwReadTemp = 0;

    static volatile CMU_CLK_REG *g_pCMUCLKReg = NULL;
    g_pCMUCLKReg = (CMU_CLK_REG *)DrvLib_MapIoSpace(BASE_REG_PA_CMU_CLK, sizeof(CMU_CLK_REG), FALSE);
    if (g_pCMUCLKReg == NULL)
    {
        RETAIL_2D_MSG(DISP_ZONE_ERROR, (_T("[G2D] g_pCMUCLKReg: DrvLib_MapIoSpace() Failed \n\r")));
        return;
    }

    g_pCMUCLKReg->CLK_SRC.CLK_SRC2 = ((g_pCMUCLKReg->CLK_SRC.CLK_SRC2 & ~(BW_MUX_G2D_SEL<<BP_MUX_G2D_SEL)) |
        (MUXG2D_SCLKMPLL<<BP_MUX_G2D_SEL));
    // Mux Status Check
    dwTimeOut = 10000;
    do
    {
        dwReadTemp = g_pCMUCLKReg->CLK_MUX_STAT.CLK_MUX_STAT1;
        if(dwTimeOut-- == 0)
            break;
    }while(dwReadTemp  & (0x8<<BP_MUX_G2D_STAT));

    g_pCMUCLKReg->CLK_DIV.CLK_DIV2 = (g_pCMUCLKReg->CLK_DIV.CLK_DIV2 & ~(BW_DIV_G2D_RATIO<<BP_DIV_G2D_RATIO) |
                                        (0x2<<BP_DIV_G2D_RATIO));
    // Divider Status Check
    dwTimeOut = 10000;
    do
    {
        dwReadTemp = g_pCMUCLKReg->CLK_DIV_STAT.CLK_DIV_STAT1;
        if(dwTimeOut-- == 0)
            break;
    }while(dwReadTemp  & (DIV_STAT_ON_CHANGING<<BP_DIV_G2D_STAT));
}


void
FIMG2D::CacheFlush(VOID *pAddress, DWORD width_byte, DWORD height, DWORD stride, DWORD left_byte, DWORD flags)
{
    if (flags == INVALIDATE)
    {
        if ((width_byte*height >= 512*1024) || (width_byte == stride)) 
        {
            CacheRangeFlush((PBYTE)pAddress, stride*height, CACHE_SYNC_DISCARD);
        } 
        else 
        {                
            InvalidateDCacheForG2D((PBYTE)pAddress + left_byte, width_byte, height, stride);
        }          
    }
    else if (flags == CLEAN)
    {
        if ((width_byte*height >= 512*1024) || (width_byte == stride)) 
        {
            CacheRangeFlush((PBYTE)pAddress, stride*height, CACHE_SYNC_WRITEBACK);
        } 
        else 
        {                
            CleanDCacheForG2D((PBYTE)pAddress + left_byte, width_byte, height, stride);
        } 
    }    
    else if (flags == CLEAN_AND_INVALIDATE)
    {
        if ((width_byte*height >= 512*1024) || (width_byte == stride)) 
        {
            CacheRangeFlush((PBYTE)pAddress, stride*height, CACHE_SYNC_DISCARD);
        } 
        else 
        {                
            CleanAndInvalidateDCacheForG2D((PBYTE)pAddress + left_byte, width_byte, height, stride);
        } 
    }
}


#ifndef FIMG_C_MODEL
inline
void
FIMG2D::g2d_wd_reg (DWORD Addr, DWORD Data)
{
    volatile DWORD *pbReg = ((volatile DWORD *)(((BYTE *)m_pG2DReg) + (Addr)));
    *pbReg = (DWORD)Data;
}


inline
DWORD
FIMG2D::g2d_rd_reg(DWORD Addr)
{
    volatile DWORD *pbReg = ((volatile DWORD *)(((BYTE *)m_pG2DReg) + (Addr)));
    DWORD Data = (DWORD) *pbReg;
    return Data;
}
#endif


BOOL 
FIMG2D::InitializeInterrupt(void)
{
    DWORD dwIRQ;

    dwIRQ = IRQ_2D;                    // 2D Accelerator IRQ
    m_dwSysIntr2D = SYSINTR_UNDEFINED;
    m_hInterrupt2D = NULL;

    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIRQ, sizeof(DWORD), &m_dwSysIntr2D, sizeof(DWORD), NULL))
    {
        m_dwSysIntr2D = SYSINTR_UNDEFINED;
        return FALSE;
    }
    RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] 2D Sysintr : %d\r\n"),m_dwSysIntr2D));

    m_hInterrupt2D = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(NULL == m_hInterrupt2D)
    {
        return FALSE;
    }

    if (!(InterruptInitialize(m_dwSysIntr2D, m_hInterrupt2D, 0, 0)))
    {
        return FALSE;
    }
    InterruptDone(m_dwSysIntr2D); 
    return TRUE;
}


void FIMG2D::DeinitInterrupt(void)
{
    if (m_dwSysIntr2D != SYSINTR_UNDEFINED)
    {
        InterruptDisable(m_dwSysIntr2D);
    }

    if (m_hInterrupt2D != NULL)
    {
        CloseHandle(m_hInterrupt2D);
    }

    if (m_dwSysIntr2D != SYSINTR_UNDEFINED)
    {
        KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &m_dwSysIntr2D, sizeof(DWORD), NULL, 0, NULL);
    }
}


void FIMG2D::IntEnable(void)
{
#ifndef FIMG_C_MODEL
    g2d_wd_reg(INTEN_REG, 0x1);
#endif
}


void FIMG2D::IntDisable(void)
{
    g2d_wd_reg(INTEN_REG, 0x0);
}


void FIMG2D::SoftReset(void)
{
    g2d_wd_reg(SOFT_RESET_REG, 0x1);
}


void FIMG2D::IntPendingClear(void)
{
    // Command Finished Pending register clear
    g2d_wd_reg(INTC_PEND_REG, 0x1);
}


void FIMG2D::StartBlt(void)
{
    g2d_wd_reg(BITBLT_START_REG, 0x1);
}


BOOL FIMG2D::StartG2D(DWORD dwProcessingType)
{
    BOOL bReturnVal = TRUE;
    
    switch(dwProcessingType)
    {
        case G2D_FASTRETURN_INT:
            IntEnable();
            StartBlt(); 
            break;

        case G2D_FASTRETURN_POL:
            StartBlt();
            break;
            
        case G2D_INTERRUPT:
            IntEnable();
            StartBlt();     
            if(!WaitForIdleInterrupt()) 	// wait until Bliting is finished using interrupt.
            {
                bReturnVal = FALSE;
            }
            break;

        case G2D_BUSYWAITING:
            StartBlt(); 
            if (!WaitForIdlePolling(G2D_POLLING_TIMEOUT_COUNT))  // wait until Bltting is finished using polling
            {
                bReturnVal = FALSE;
            }
            break;
    }

    return bReturnVal;

}


BOOL FIMG2D::WaitForIdleInterrupt(void)
{
#ifdef FIMG_C_MODEL    
    return TRUE;
#endif
    DWORD bValue = TRUE;

    if(WAIT_TIMEOUT == WaitForSingleObject(m_hInterrupt2D, G2D_INTERRUPT_TIMEOUT_VALUE))
    {
        RETAIL_2D_MSG(DISP_ZONE_ERROR, (_T("[G2D] WaitForSingleObject Time Out %dms\n"),G2D_INTERRUPT_TIMEOUT_VALUE));
        bValue = WaitForIdlePolling(10000);
    }

    IntDisable();
    IntPendingClear();     
    InterruptDone(m_dwSysIntr2D); 
    return bValue;
}


BOOL FIMG2D::WaitForIdlePolling(DWORD dwPollingCnt)
{
#ifdef FIMG_C_MODEL    
    return TRUE;
#endif

    for(DWORD i=0;i<dwPollingCnt;i++)
    {
        if(g2d_rd_reg(FIFO_STAT_REG) & 0x1)
        {
            break;
        }
        if(i>=(dwPollingCnt-1))
        {
            RETAIL_2D_MSG(DISP_ZONE_ERROR, (_T("[G2D] WaitForIdlepolling Timeout count %d\n"),dwPollingCnt));
            SoftReset();
            return FALSE;
        }
    }
return TRUE;
}
    

BOOL FIMG2D::IsRunning(void)
{
    BOOL bValue = FALSE;
    bValue = (!(BOOL)(g2d_rd_reg(FIFO_STAT_REG) & 0x1));
    return bValue;
}


void FIMG2D::SurfCacheClear(void)
{
#ifdef FIMG_C_MODEL    
    return;
#endif

    g2d_wd_reg(CACHECTL_REG, 0x7);
}


/**
*   @fn     int SMDKDisp::GetRelativeDegree(int SourceDegree, int DestinationDegree)
*   @brief  Get Reletive Rotation Degree From Source Degree and Destination Degreee
*   @param  pBltParms Blit Parameter Information Structure
*   @note   DMDO_0 = 0, DMDO_90 = 1, DMDO_180 = 2, DMDO_270 = 4
*/
DWORD 
FIMG2D::GetRelativeDegree(DWORD SrcDegree, DWORD DstDegree)
{
    switch(SrcDegree)
    {
        default:
        case DMDO_0:
            switch(DstDegree)
            {
                default:
                case DMDO_0:    return DMDO_0;
                case DMDO_90:   return DMDO_90;
                case DMDO_180:  return DMDO_180;
                case DMDO_270:  return DMDO_270;
            }
        case DMDO_90:
            switch(DstDegree)
            {
                default:
                case DMDO_0:    return DMDO_270;
                case DMDO_90:   return DMDO_0;
                case DMDO_180:  return DMDO_90;
                case DMDO_270:  return DMDO_180;
            }
        case DMDO_180:
            switch(DstDegree)
            {
                default:
                case DMDO_0:    return DMDO_180;
                case DMDO_90:   return DMDO_270;
                case DMDO_180:  return DMDO_0;
                case DMDO_270:  return DMDO_90;
            }
        case DMDO_270:
            switch(DstDegree)
            {
                default:
                case DMDO_0:    return DMDO_90;
                case DMDO_90:   return DMDO_180;
                case DMDO_180:  return DMDO_270;
                case DMDO_270:  return DMDO_0;
            }
    }
}


DWORD
FIMG2D::Is_Overlapped_Rect(GPEBltParms *pBltParms, PRECTL prclDst, PRECTL prclSrc)
{
    if( prclDst->left >= prclSrc->left && prclDst->left <= prclSrc->right &&
        prclDst->top >= prclSrc->top && prclDst->top <= prclSrc->bottom )
    {
        return RIGHT_DOWN_DIRECTION;
    }
    else if( prclDst->left >= prclSrc->left && prclDst->left <= prclSrc->right &&
        prclDst->bottom >= prclSrc->top && prclDst->bottom <= prclSrc->bottom )
    {
        return RIGHT_UP_DIRECTION;
    }

    else if( prclDst->right <= prclSrc->right && prclDst->right >= prclSrc->left &&
        prclDst->bottom <= prclSrc->bottom && prclDst->bottom >= prclSrc->top )
    {
        return LEFT_UP_DIRECTION;
    }
    else if( prclDst->right >= prclSrc->left && prclDst->right <= prclSrc->right &&
        prclDst->top >= prclSrc->top && prclDst->top <= prclSrc->bottom )
    {
        return LEFT_DOWN_DIRECTION;
    }
    else
    {
        return NO_OVERLAPPED;
    }
}


DWORD 
FIMG2D::GetHWColorFormat(GPESurf *pSurf)
{
    DWORD dw2DHWColorFormat = G2D_COLOR_UNUSED;

    if(pSurf)
    {
        GPEFormat * pFormat;
        pFormat = pSurf->FormatPtr();

        if (pSurf->Format() == gpe16Bpp)
        {
            RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat 16bpp!!\r\n")));

            if (pFormat->m_pPalette)
            {
                if (pFormat->m_PaletteEntries == 3 &&
                    pFormat->m_pPalette[0] == 0x0000f800 && // R
                    pFormat->m_pPalette[1] == 0x000007e0 && // G
                    pFormat->m_pPalette[2] == 0x0000001f) // B
                {
                    dw2DHWColorFormat = G2D_COLOR_RGB_565;
                }
                else if (pFormat->m_PaletteEntries == 3 &&
                    pFormat->m_pPalette[0] == 0x00007c00 &&    // R
                    pFormat->m_pPalette[1] == 0x000003e0 &&    // G
                    pFormat->m_pPalette[2] == 0x0000001f)      // B
                {
                    RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat G2D_COLOR_XRGB_1555\r\n")));
                    dw2DHWColorFormat = G2D_COLOR_XRGB_1555;//G2D_COLOR_UNUSED;//
                }
                else if (pFormat->m_PaletteEntries == 3 &&
                    pFormat->m_pPalette[0] == 0x0000001f &&    // B
                    pFormat->m_pPalette[1] == 0x000003e0 &&    // G
                    pFormat->m_pPalette[2] == 0x00007c00)      // R
                {
                    RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat G2D_COLOR_XBGR_1555\r\n")));
                    dw2DHWColorFormat = G2D_COLOR_XBGR_1555;//G2D_COLOR_ARGB_1555;//
                }
                else if (pFormat->m_PaletteEntries == 4 &&
                    pFormat->m_pPalette[3] == 0x00008000 &&    // A
                    pFormat->m_pPalette[0] == 0x00007c00 &&    // R
                    pFormat->m_pPalette[1] == 0x000003e0 &&    // G
                    pFormat->m_pPalette[2] == 0x0000001f)      // B
                {
                    RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat G2D_COLOR_XBGR_1555\r\n")));
                    dw2DHWColorFormat = G2D_COLOR_ARGB_1555;
                }
                else 
                {
                    RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat->m_PaletteEntries=%08x\r\n"), pFormat->m_PaletteEntries));
                    for (int i=0; i<pFormat->m_PaletteEntries; i++)
                    {
                        RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] %d : 0x%08x\r\n"), i, pFormat->m_pPalette[i]));
                    }
                    dw2DHWColorFormat = G2D_COLOR_UNUSED;
                }
            }
            else
            {
                RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] 16bit Surface Format HAS NO PALETTE, we assume it's RGB565\r\n")));
                if(m_G2DAccelArgs.UseForceSetPallete)                
                    dw2DHWColorFormat = G2D_COLOR_RGB_565;
                else
                    dw2DHWColorFormat = G2D_COLOR_UNUSED;
            }
        }
        else if (pSurf->Format() == gpe24Bpp)
        {
            RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat 24bpp!!\r\n")));

            if (pFormat->m_pPalette)
            {
                if (pFormat->m_PaletteEntries == 3 &&
                    pFormat->m_pPalette[0] == 0x00FF0000 && // R
                    pFormat->m_pPalette[1] == 0x0000FF00 && // G
                    pFormat->m_pPalette[2] == 0x000000FF) // B
                {
                    RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat G2D_COLOR_PACKED_RGB_888\r\n")));
                    dw2DHWColorFormat = G2D_COLOR_PACKED_RGB_888;
                }
                else 
                {
                    RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] 24bpp unsupported pFormat->m_PaletteEntries=%08x\r\n"), pFormat->m_PaletteEntries));
                    for (int i=0; i<pFormat->m_PaletteEntries; i++)
                    {
                        RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] %d : 0x%08x\r\n"), i, pFormat->m_pPalette[i]));
                    }
                    dw2DHWColorFormat = G2D_COLOR_UNUSED;
                }
            }
            else
            {
                RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] 24bit Surface Format HAS NO PALETTE\r\n")));
                if(m_G2DAccelArgs.UseForceSetPallete)
                    dw2DHWColorFormat = G2D_COLOR_PACKED_RGB_888;
                else
                    dw2DHWColorFormat = G2D_COLOR_UNUSED;
            }
        }
        else if (pSurf->Format() == gpe32Bpp)
        {
            RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat 32bpp!!\r\n")));
            if (pFormat->m_pPalette)
            {
                if (pFormat->m_PaletteEntries == 4 &&
                    pFormat->m_pPalette[3] == 0xff000000 &&    // A
                    pFormat->m_pPalette[0] == 0x00ff0000 &&    // R
                    pFormat->m_pPalette[1] == 0x0000ff00 &&    // G
                    pFormat->m_pPalette[2] == 0x000000ff)      // B
                {
                    dw2DHWColorFormat = G2D_COLOR_ARGB_8888;
                }
                else if (//pFormat->m_PaletteEntries == 3 &&
                    pFormat->m_pPalette[0] == 0x00ff0000 && // R
                    pFormat->m_pPalette[1] == 0x0000ff00 && // G
                    pFormat->m_pPalette[2] == 0x000000ff)   // B
                {
                    dw2DHWColorFormat = G2D_COLOR_XRGB_8888;
                }
                else if (pFormat->m_PaletteEntries == 4 &&
                    pFormat->m_pPalette[3] == 0x000000ff &&    // A
                    pFormat->m_pPalette[0] == 0xff000000 &&    // R
                    pFormat->m_pPalette[1] == 0x00ff0000 &&    // G
                    pFormat->m_pPalette[2] == 0x0000ff00)      // B
                {
                    dw2DHWColorFormat = G2D_COLOR_RGBA_8888;
                }
                else  if (//pFormat->m_PaletteEntries == 3 &&
                    pFormat->m_pPalette[0] == 0xff000000 && // R
                    pFormat->m_pPalette[1] == 0x00ff0000 && // G
                    pFormat->m_pPalette[2] == 0x0000ff00)   // B
                {
                    dw2DHWColorFormat = G2D_COLOR_RGBX_8888;
                }
                else 
                {
                    RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat->m_PaletteEntries=%08x\r\n"), pFormat->m_PaletteEntries));
                    for (int i = 0; i<pFormat->m_PaletteEntries; i++)
                    {
                        RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] %d : 0x%08x\r\n"), i, pFormat->m_pPalette[i]));
                    }
                    dw2DHWColorFormat = G2D_COLOR_UNUSED;
                }
            }
            else
            {
                RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] 32bit Surface Format HAS NO PALETTE\r\n")));
                if(m_G2DAccelArgs.UseForceSetPallete)
                    dw2DHWColorFormat = G2D_COLOR_ARGB_8888;
                else
                    dw2DHWColorFormat = G2D_COLOR_UNUSED;
            }
        }
        else
        {
            RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] Format:%d\n"),pSurf->Format()));
            RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] pFormat unknown!!\r\n")));
        }
        
        return dw2DHWColorFormat;        
    }

    RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] Illegal Surface\n\r")));

    return dw2DHWColorFormat;
}


void
FIMG2D::RotateRectl(RECTL *prcl, GPESurf *orgSurf)
{
    RECTL rclSwap = *prcl;

    switch (orgSurf->Rotate())
    {
        case DMDO_90:
            prcl->left   = rclSwap.top;
            prcl->right  = rclSwap.bottom;
            prcl->top    = orgSurf->Width() - rclSwap.right;
            prcl->bottom = orgSurf->Width() - rclSwap.left;
            break;

        case DMDO_180:
            prcl->left   = orgSurf->Width() - rclSwap.right;
            prcl->right  = orgSurf->Width() - rclSwap.left;
            prcl->top    = orgSurf->Height() - rclSwap.bottom;
            prcl->bottom = orgSurf->Height() - rclSwap.top;
            break;

        case DMDO_270:
            prcl->left   = orgSurf->Height() - rclSwap.bottom;
            prcl->right  = orgSurf->Height() - rclSwap.top;
            prcl->top    = rclSwap.left;
            prcl->bottom = rclSwap.right;
            break;

        default:
            break;
    }
}


SCODE
FIMG2D::Calculate_Directions(GPEBltParms *pBltParms, PRECTL prclDst, PRECTL prclSrc)
{
    int     iRotate = DMDO_0;
    int     x_AxisFlip = 0;
    int     y_AxisFlip = 0;

    m_dwEnableRotate90 = ROTATE_FALSE;

    if(pBltParms->pSrc)
    {
        if(pBltParms->pSrc->IsRotate())
        {
            RotateRectl(prclSrc, pBltParms->pSrc);
        }
    }

    if(pBltParms->pDst->IsRotate())
    {   
        RotateRectl(prclDst, pBltParms->pDst);
    }

    if(pBltParms->pSrc)
    {
        /// Set Relative Rotation Degree
        iRotate = GetRelativeDegree(pBltParms->pSrc->Rotate(), pBltParms->pDst->Rotate());
    }
    else
    {
        /// Set Relative Rotation Degree
        iRotate = pBltParms->pDst->Rotate();
    }

    if(prclDst->top > prclDst->bottom)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] prclDst X-Axis\r\n")));
        x_AxisFlip = 1;
        SWAP(prclDst->top, prclDst->bottom, LONG);
    }

    if(prclDst->left > prclDst->right)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] prclDst Y-Axis\r\n")));
        y_AxisFlip = 1;
        SWAP(prclDst->left, prclDst->right, LONG);
    }

    m_dwSrcDirectionX = POSITIVE_DIRECTION;
    m_dwSrcDirectionY = POSITIVE_DIRECTION;

    if(x_AxisFlip == 0 && y_AxisFlip == 0)
    {
        switch(iRotate)
        {
            case DMDO_0: // ROTATE_0
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 00 ROTATE 0\r\n")));
                m_dwDstDirectionX = POSITIVE_DIRECTION;
                m_dwDstDirectionY = POSITIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_FALSE;
                iRotate = 0;
                break;
            case DMDO_90: // ROTATE_90
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 00 ROTATE 270\r\n")));
                m_dwDstDirectionX = NEGATIVE_DIRECTION;
                m_dwDstDirectionY = NEGATIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_TRUE;
                break;
            case DMDO_180: // ROTATE_180
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 00 ROTATE 180\r\n")));
                m_dwDstDirectionX = NEGATIVE_DIRECTION;
                m_dwDstDirectionY = NEGATIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_FALSE;
                break;
            case DMDO_270: // ROTATE_270
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 00 ROTATE 90\r\n")));
                m_dwDstDirectionX = POSITIVE_DIRECTION;
                m_dwDstDirectionY = POSITIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_TRUE;
                break;
        }
    }
    else if(x_AxisFlip == 1 && y_AxisFlip == 1)    
    {
        switch( iRotate )
        {
            case DMDO_180: // ROTATE_180
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 11 ROTATE 180\r\n")));
                m_dwDstDirectionX = POSITIVE_DIRECTION;
                m_dwDstDirectionY = POSITIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_FALSE;
                iRotate = 0;
                break;
            case DMDO_90: // ROTATE_270
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 11 ROTATE 270\r\n")));
                m_dwDstDirectionX = POSITIVE_DIRECTION;
                m_dwDstDirectionY = POSITIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_TRUE;
                break;
            case DMDO_0: // ROTATE_0
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 11 ROTATE 0\r\n")));
                m_dwDstDirectionX = NEGATIVE_DIRECTION;
                m_dwDstDirectionY = NEGATIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_FALSE;
                break;
            case DMDO_270: // ROTATE_90
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 11 ROTATE 90\r\n")));
                m_dwDstDirectionX = NEGATIVE_DIRECTION;
                m_dwDstDirectionY = NEGATIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_TRUE;
                break;
        }
    }
    else if(x_AxisFlip == 0 && y_AxisFlip == 1)    
    {
        switch( iRotate )
        {
            case DMDO_0: // ROTATE_0
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 01 ROTATE 0\r\n")));
                m_dwDstDirectionX = NEGATIVE_DIRECTION;
                m_dwDstDirectionY = POSITIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_FALSE;
                iRotate = 0;
                break;
            case DMDO_270: // ROTATE_90
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 01 ROTATE 90\r\n")));
                m_dwDstDirectionX = NEGATIVE_DIRECTION;
                m_dwDstDirectionY = POSITIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_TRUE;
                break;
            case DMDO_180: // ROTATE_180
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 01 ROTATE 180\r\n")));
                m_dwDstDirectionX = POSITIVE_DIRECTION;
                m_dwDstDirectionY = NEGATIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_FALSE;
                break;
            case DMDO_90: // ROTATE_270
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 01 ROTATE 270\r\n")));
                m_dwDstDirectionX = POSITIVE_DIRECTION;
                m_dwDstDirectionY = NEGATIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_TRUE;
                break;
        }
    }
    else if(x_AxisFlip == 1 && y_AxisFlip == 0)    
    {
        switch( iRotate )
        {
            case DMDO_180: // ROTATE_180
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 10 ROTATE 180\r\n")));
                m_dwDstDirectionX = NEGATIVE_DIRECTION;
                m_dwDstDirectionY = POSITIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_FALSE;
                iRotate = 0;
                break;
            case DMDO_90: // ROTATE_270
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 10 ROTATE 270\r\n")));
                m_dwDstDirectionX = NEGATIVE_DIRECTION;
                m_dwDstDirectionY = POSITIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_TRUE;
                break;
            case DMDO_0: // ROTATE_0
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 10 ROTATE 0\r\n")));
                m_dwDstDirectionX = POSITIVE_DIRECTION;
                m_dwDstDirectionY = NEGATIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_FALSE;
                break;
            case DMDO_270: // ROTATE_90
                RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] 10 ROTATE 90\r\n")));
                m_dwDstDirectionX = POSITIVE_DIRECTION;
                m_dwDstDirectionY = NEGATIVE_DIRECTION;  
                m_dwEnableRotate90 = ROTATE_TRUE;
                break;
        }
    }

    return S_OK;
}


BOOL 
FIMG2D::CreateCloneBuffer(GPESurf* orgSurf, SURFACE_DESCRIPTOR *descSurf, PRECTL prcl, DWORD bType)
{
    if((RECT_WIDTH(prcl) * RECT_HEIGHT(prcl) * orgSurf->BytesPerPixel()) > (G2D_CLONESURF_WIDTH * G2D_CLONESURF_HEIGHT * 4))
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] Surfcace RECT Size > CLONEBUFFERSIZE Failed\n")));
        return FALSE;
    }

    if(bType == SRC_BUFFER)
    {
        descSurf->dwPhyBaseaddr = m_sCloneBuffer.dwSrc_Phy;
        descSurf->pdwBaseaddr = m_sCloneBuffer.pdwSrc_Vir;
    }
    else if(bType == DST_BUFFER)
    {
        descSurf->dwPhyBaseaddr = m_sCloneBuffer.dwDst_Phy;
        descSurf->pdwBaseaddr = m_sCloneBuffer.pdwDst_Vir;
    }

    descSurf->sRcl.top = 0;
    descSurf->sRcl.left = 0;
    descSurf->sRcl.right = RECT_WIDTH(prcl);
    descSurf->sRcl.bottom = RECT_HEIGHT(prcl);
    descSurf->dwStride = RECT_WIDTH(prcl)*orgSurf->BytesPerPixel();
    descSurf->dwBaseaddr = ((DWORD)descSurf->pdwBaseaddr);

    return TRUE;
}


BOOL 
FIMG2D::ReleaseCloneBuffer(void)
{
    BOOL bError = TRUE;
    
    if (m_descSrcSurface.pdwBaseaddr)
    {
        m_descSrcSurface.pdwBaseaddr = NULL;
        m_descSrcSurface.dwPhyBaseaddr = NULL;
    }
    if (m_descDstSurface.pdwBaseaddr)
    {
        m_descDstSurface.pdwBaseaddr = NULL;
        m_descDstSurface.dwPhyBaseaddr = NULL;
    }    

    return bError;
}


BOOL 
FIMG2D::CopyCloneBuffer(GPESurf* orgSurf, SURFACE_DESCRIPTOR descSurf, RECTL prcl, BOOL bDirection)
{
    struct
    {
        BYTE *pCloneAddr;
        BYTE *pSurfAddr;
        DWORD dwCloneStride;
        DWORD dwSurfStride;
        DWORD dwHeight;
    }sData;

    sData.pCloneAddr = (BYTE *)descSurf.pdwBaseaddr;
    sData.pSurfAddr = (BYTE *)orgSurf->Buffer() + prcl.top*orgSurf->Stride() + prcl.left*orgSurf->BytesPerPixel();
    sData.dwCloneStride = descSurf.dwStride;
    sData.dwSurfStride = orgSurf->Stride();
    sData.dwHeight = descSurf.sRcl.bottom;

    if(bDirection == CLONETOSURF)
    { 
        CacheFlush((PBYTE)sData.pCloneAddr,
            sData.dwCloneStride, sData.dwHeight, sData.dwCloneStride, 0, INVALIDATE);   
    }
    
    // Now below asm functions are not implemented yet....
#ifdef COPYCLONEBUFFER_ASM_OPTIMIZE
    if(bDirection == SURFTOCLONE)
    {
        SurfToClone_ASM(&sData);
    }
    else
    {
        CloneToSurf_ASM(&sData);
    }
#else
    for(int i=0; i<(int)sData.dwHeight; i++)
    {
        if(bDirection == SURFTOCLONE)
        {
            memcpy(sData.pCloneAddr + (sData.dwCloneStride*i),
                sData.pSurfAddr + (sData.dwSurfStride*i), sData.dwCloneStride);
        }
        else if(bDirection == CLONETOSURF)
        {
            memcpy(sData.pSurfAddr + (sData.dwSurfStride*i),
                sData.pCloneAddr + (sData.dwCloneStride*i), sData.dwCloneStride);
        }
    }
#endif

    return TRUE;
}


// Provides a physical address for a given user mode virtual address.
BOOL 
FIMG2D::GetPhyAddress(DWORD * pdwVirtual, DWORD * pdwPhysical)
{
    BOOL bReturnVal = TRUE;
    DWORD dwPageSize = UserKInfo[KINX_PAGESIZE];
    DWORD dwPageTableEntry;
    DWORD dwPageTablePart;
    DWORD dwOffsetInPage;

    /* query the page tables */
    if (LockPages (pdwVirtual, sizeof (DWORD), &dwPageTableEntry, LOCKFLAG_QUERY_ONLY) != TRUE)
    {
        bReturnVal = FALSE;
        RETAIL_2D_MSG(DISP_ZONE_ERROR,(_T("[G2D] GetPhyAddress Failed!\n"))); 
        goto cleanAndReturn;
    }

    /* shift left to make into a real address */
    dwPageTablePart = dwPageTableEntry << UserKInfo[KINX_PFN_SHIFT];

    /* figure out the offset in the page */
    dwOffsetInPage = ((DWORD) pdwVirtual) & (~UserKInfo[KINX_PFN_MASK]);

    /* combine the page table part and offset to create the address */
    *pdwPhysical = dwPageTablePart | dwOffsetInPage;

    cleanAndReturn:

    return (bReturnVal);
}


BOOL
FIMG2D::SetSourceSurf(GPEBltParms *pBltParms, RECTL rcl)
{
    if(pBltParms->pSrc != NULL)
    {
        m_descSrcSurface.sRcl = rcl;
        m_descSrcSurface.dwStride = pBltParms->pSrc->Stride();

        if(m_descSrcSurface.dwPhyBaseaddr == NULL)
        {
            if (!CreateCloneBuffer(pBltParms->pSrc, &m_descSrcSurface, &rcl, SRC_BUFFER))
            {
                return FALSE;
            }

            CopyCloneBuffer(pBltParms->pSrc, m_descSrcSurface, rcl, SURFTOCLONE);
        }
        else
        {
            m_descSrcSurface.dwBaseaddr = ((DWORD)pBltParms->pSrc->Buffer());
            if (!GetPhyAddress((DWORD *)m_descSrcSurface.dwBaseaddr, &m_descSrcSurface.dwPhyBaseaddr))
            {
                return FALSE;
            }
        }

        g2d_wd_reg(SRC_SELECT_REG, NORMAL_MODE);
#ifdef FIMG_C_MODEL     
        g2d_wd_reg(SRC_BASE_ADDR_REG, m_descSrcSurface.dwBaseaddr);
#else
        g2d_wd_reg(SRC_BASE_ADDR_REG, m_descSrcSurface.dwPhyBaseaddr);
#endif
        g2d_wd_reg(SRC_STRIDE_REG, m_descSrcSurface.dwStride);
        g2d_wd_reg(SRC_COLOR_MODE_REG, m_descSrcSurface.dwColorMode);
        g2d_wd_reg(SRC_LEFT_TOP_REG, ((m_descSrcSurface.sRcl.top<<16)|m_descSrcSurface.sRcl.left));
        g2d_wd_reg(SRC_RIGHT_BOTTOM_REG, ((m_descSrcSurface.sRcl.bottom<<16)|m_descSrcSurface.sRcl.right));

        g2d_wd_reg(FG_COLOR_REG, 0); // Black
        g2d_wd_reg(THIRD_OPERAND_REG, (THIRD_FOREGROUND<<IDX_MASKED_SELECT | THIRD_FOREGROUND));

        if ((pBltParms->bltFlags & BLT_TRANSPARENT) && (pBltParms->solidColor != -1)) 
        {
            m_sCMD.dwTransParentMode = TRUE;        
            g2d_wd_reg(BS_COLOR_REG, pBltParms->solidColor); 
        }    
        else if(pBltParms->solidColor != -1)
        {   
            g2d_wd_reg(FG_COLOR_REG, pBltParms->solidColor); // Black
            RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] This ROP4 is using Solid Color...\r\n")));
        }
    }
    else// if(pBltParms->pSrc == NULL)
    {
        g2d_wd_reg(SRC_STRIDE_REG, 0);
        g2d_wd_reg(SRC_SELECT_REG, FOREGROUND_IMAGE);
        g2d_wd_reg(SRC_COLOR_MODE_REG, m_descSrcSurface.dwColorMode);
        g2d_wd_reg(FG_COLOR_REG, 0); // Black
        g2d_wd_reg(THIRD_OPERAND_REG, (THIRD_FOREGROUND<<IDX_MASKED_SELECT | THIRD_FOREGROUND));
    }

    return TRUE;
}


BOOL
FIMG2D::SetDestinationSurf(GPEBltParms *pBltParms, RECTL rcl)
{
    m_descDstSurface.sRcl = rcl;
    m_descDstSurface.dwStride = pBltParms->pDst->Stride();

    if(m_descDstSurface.dwPhyBaseaddr == NULL)
    {
        if (!CreateCloneBuffer(pBltParms->pDst, &m_descDstSurface, &rcl, DST_BUFFER))
        {
            return FALSE;
        }
        if((pBltParms->bltFlags & BLT_ALPHABLEND) && 
            (!((pBltParms->blendFunction.AlphaFormat == 0) && (pBltParms->blendFunction.SourceConstantAlpha == 0xFF))))     
        {    
            CopyCloneBuffer(pBltParms->pDst, m_descDstSurface, rcl, SURFTOCLONE);
        }
    }
    else
    {
        m_descDstSurface.dwBaseaddr = ((DWORD)pBltParms->pDst->Buffer());
        if (!GetPhyAddress((DWORD *)m_descDstSurface.dwBaseaddr, &m_descDstSurface.dwPhyBaseaddr))
        {
            return FALSE;
        }        
    }

    g2d_wd_reg(DST_SELECT_REG, NORMAL_MODE);
#ifdef FIMG_C_MODEL    
    g2d_wd_reg(DST_BASE_ADDR_REG, m_descDstSurface.dwBaseaddr);
#else
    g2d_wd_reg(DST_BASE_ADDR_REG, m_descDstSurface.dwPhyBaseaddr);
#endif
    g2d_wd_reg(DST_STRIDE_REG, m_descDstSurface.dwStride);
    g2d_wd_reg(DST_COLOR_MODE_REG, m_descDstSurface.dwColorMode);
    g2d_wd_reg(DST_LEFT_TOP_REG, ((m_descDstSurface.sRcl.top<<16)|m_descDstSurface.sRcl.left));
    g2d_wd_reg(DST_RIGHT_BOTTOM_REG, ((m_descDstSurface.sRcl.bottom<<16)|m_descDstSurface.sRcl.right));

    return TRUE;
}


BOOL
FIMG2D::SetPatternSurf(GPEBltParms *pBltParms)
{
    DWORD   dwTopIndent;
    DWORD	dwLeftIndent;

    if((pBltParms->pBrush != NULL) && (pBltParms->solidColor == -1))
    {
        // Calculate an rclBrush so that the correct starting pixel is chosen for the brush iterator
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] Pattern depth: %d Bpp, %d palette\r\n"), EGPEFormatToBpp[pBltParms->pBrush->Format()], pBltParms->pBrush->FormatPtr()->m_PaletteEntries )) ;

        m_descBrushSurface.dwBaseaddr = ((DWORD)pBltParms->pBrush->Buffer());
        if (!GetPhyAddress((DWORD *)m_descBrushSurface.dwBaseaddr, &m_descBrushSurface.dwPhyBaseaddr))
        {
            return FALSE;
        }        

        m_descBrushSurface.dwVertRes = pBltParms->pBrush->Height();    
        m_descBrushSurface.dwHoriRes = pBltParms->pBrush->Width();    
        m_descBrushSurface.dwColorMode = GetHWColorFormat(pBltParms->pBrush);
        if(m_descBrushSurface.dwColorMode == G2D_COLOR_UNUSED)
        {
            RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] 2D Brush does not support this color format pall\r\n")));
            return FALSE; 
        }

        m_dwBrushDirectionY = m_dwDstDirectionY;
        m_dwBrushDirectionX = m_dwDstDirectionX;

        dwTopIndent = (pBltParms->pptlBrush) ? pBltParms->pBrush->Height() - pBltParms->pptlBrush->y : 0;
        dwLeftIndent = (pBltParms->pptlBrush) ? pBltParms->pBrush->Width() - pBltParms->pptlBrush->x : 0;

#ifdef FIMG_C_MODEL
        g2d_wd_reg(PAT_BASE_ADDR_REG, m_descBrushSurface.dwBaseaddr);
#else
        g2d_wd_reg(PAT_BASE_ADDR_REG, m_descBrushSurface.dwPhyBaseaddr);
#endif
        g2d_wd_reg(PAT_SIZE_REG, ((m_descBrushSurface.dwVertRes<<16) | m_descBrushSurface.dwHoriRes));
        g2d_wd_reg(PAT_STRIDE_REG, pBltParms->pBrush->Stride());
        g2d_wd_reg(PAT_COLOR_MODE_REG, m_descBrushSurface.dwColorMode);
        g2d_wd_reg(PAT_OFFSET_REG, (dwTopIndent<<16 | dwLeftIndent));

        g2d_wd_reg(THIRD_OPERAND_REG, (THIRD_PATTERN<<IDX_MASKED_SELECT | THIRD_PATTERN));
    }
    else if(pBltParms->solidColor != -1 )
    {
        g2d_wd_reg(FG_COLOR_REG, pBltParms->solidColor); 
    }

    return TRUE;
}


BOOL
FIMG2D::SetMaskSurf(GPEBltParms *pBltParms)
{
    m_dwMaskDirectionX = POSITIVE_DIRECTION;
    m_dwMaskDirectionY = POSITIVE_DIRECTION;

    if(((unsigned char)(pBltParms->rop4>>8)) != ((unsigned char)pBltParms->rop4) )
    {
        if(!(pBltParms->pMask))
        {
            return FALSE; 
        }
        
        m_sCMD.dwMaskEn = TRUE;
        m_descMaskSurface.dwBaseaddr = (DWORD)pBltParms->pMask->Buffer();
        if (!GetPhyAddress((DWORD *)m_descMaskSurface.dwBaseaddr, &m_descMaskSurface.dwPhyBaseaddr))
        {
            return FALSE;
        }   

        m_dwMaskDirectionX = m_dwSrcDirectionX;
        m_dwMaskDirectionY = m_dwSrcDirectionY;

        if(pBltParms->pSrc == NULL)
        { 
            g2d_wd_reg(SRC_STRIDE_REG, pBltParms->pMask->Stride());
            g2d_wd_reg(SRC_LEFT_TOP_REG, ((pBltParms->prclMask->top<<16)|pBltParms->prclMask->left));
            g2d_wd_reg(SRC_RIGHT_BOTTOM_REG, ((pBltParms->prclMask->bottom<<16)|pBltParms->prclMask->right));
        }
        else
        {
            RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] MASK with SRC Surface\r\n")));
            return FALSE;
        }

        if(pBltParms->pMask->Format() == gpe1Bpp )
        {
            m_sCMD.dwMaskEn = TRUE;
#ifdef FIMG_C_MODEL                
            g2d_wd_reg(MASK_BASE_ADDR_REG, m_descMaskSurface.dwBaseaddr);
#else
            g2d_wd_reg(MASK_BASE_ADDR_REG, m_descMaskSurface.dwPhyBaseaddr);
#endif
            g2d_wd_reg(MASK_STRIDE_REG, pBltParms->pMask->Stride());
        }
    }

    return TRUE;
}


BOOL
FIMG2D::SetClipRectl(PRECTL prclClip, RECTL rclDst)
{
    DWORD   dwOutofClipRange=0;

    m_sCMD.dwCWEn = TRUE;

    if(prclClip->top > prclClip->bottom)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] rclClip X-Axis\r\n")));      
        SWAP(prclClip->top, prclClip->bottom, LONG);
    }

    if(prclClip->left > prclClip->right)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] rclClip Y-Axis\r\n")));
        SWAP(prclClip->left, prclClip->right, LONG);
    }


    if(prclClip->left < rclDst.left)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] rclClip left out of dst rect\r\n")));

        dwOutofClipRange++;
        prclClip->left = rclDst.left; 
    }

    if(prclClip->top < rclDst.top)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] rclClip top out of dst rect\r\n")));
        dwOutofClipRange++;
        prclClip->top = rclDst.top; 
    }

    if(prclClip->right > rclDst.right)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] rclClip right out of dst rect\r\n")));
        dwOutofClipRange++;
        prclClip->right = rclDst.right; 
    }

    if(prclClip->bottom > rclDst.bottom)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] rclClip bottom out of dst rect\r\n")));
        dwOutofClipRange++;
        prclClip->bottom = rclDst.bottom; 
    }

    if(prclClip->left >= prclClip->right)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] rclClip.left > rclClip.right\r\n")));	
        return FALSE;
    }

    if(prclClip->top >= prclClip->bottom)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] rclClip.top > rclClip.bottom\r\n")));	    
        return FALSE;
    }

    if(dwOutofClipRange == 4)
    {
        RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] All of rclClip is out of dst rect!!!! So Blt just DST rect!!\r\n")));
        m_sCMD.dwCWEn = FALSE;
    }

    g2d_wd_reg(CW_LEFT_TOP_REG, (prclClip->top<<16)|(prclClip->left));
    g2d_wd_reg(CW_RIGHT_BOTTOM_REG, ((prclClip->bottom<<16)|prclClip->right));

    return TRUE;
}


#ifdef USE_OALFLUSH
void
FIMG2D::CacheFlushForSurf(GPEBltParms *pBltParms, PRECTL prclSrc, PRECTL prclDst, PRECTL prclClip, G2D_ACCEL_CONTROL_ARGS m_G2DAccelArgs)
{
    if((pBltParms->pSrc) && (!m_descSrcSurface.pdwBaseaddr))
    {
        if (!pBltParms->pSrc->InVideoMemory())
        {
            if(pBltParms->pSrc->Stride()>0)
            {
                CacheRangeFlush((PBYTE)pBltParms->pSrc->Buffer() + pBltParms->prclSrc->top*pBltParms->pSrc->Stride(),
                    RECT_HEIGHT(pBltParms->prclSrc) * ABS(pBltParms->pSrc->Stride()), CACHE_SYNC_DISCARD);     
            }
            else
            {
                CacheRangeFlush((PBYTE)pBltParms->pSrc->Buffer() - (pBltParms->pSrc->Height()-1) * ABS(pBltParms->pSrc->Stride())
                    + (pBltParms->pSrc->Height() - pBltParms->prclSrc->bottom) * ABS(pBltParms->pSrc->Stride()),
                    RECT_HEIGHT(pBltParms->prclSrc) * ABS(pBltParms->pSrc->Stride()), CACHE_SYNC_DISCARD);     
            }
        }
    }          

    if((pBltParms->pDst) && (!m_descDstSurface.pdwBaseaddr))
    {
        if (!pBltParms->pDst->InVideoMemory() || (m_G2DAccelArgs.UseCachedVideoMemory && m_G2DAccelArgs.UseCacheFlushForVideoMemory))
        {    
            if(pBltParms->pDst->Stride()>0)
            {
                if (pBltParms->pDst->IsRotate() && (pBltParms->bltFlags & BLT_STRETCH))
                {
                    CacheRangeFlush((PBYTE)pBltParms->pDst->Buffer(),
                        pBltParms->pDst->Height() * ABS(pBltParms->pDst->Stride()), CACHE_SYNC_DISCARD);             
                }
                else
                {
                    CacheRangeFlush((PBYTE)pBltParms->pDst->Buffer() + prclDst->top*pBltParms->pDst->Stride(),
                        RECT_HEIGHT(prclDst) * ABS(pBltParms->pDst->Stride()), CACHE_SYNC_DISCARD);                     
                }                        
            }
            else
            {
                if (pBltParms->pDst->IsRotate() && (pBltParms->bltFlags & BLT_STRETCH))
                {
                    CacheRangeFlush((PBYTE)pBltParms->pDst->Buffer() - (pBltParms->pDst->Height()-1) * ABS(pBltParms->pDst->Stride()),
                        pBltParms->pDst->Height() * ABS(pBltParms->pDst->Stride()), CACHE_SYNC_DISCARD);     
                }
                else
                {
                    CacheRangeFlush((PBYTE)pBltParms->pDst->Buffer() - (pBltParms->pDst->Height()-1) * ABS(pBltParms->pDst->Stride())
                        + (pBltParms->pDst->Height() - prclDst->bottom) * ABS(pBltParms->pDst->Stride()),
                        RECT_HEIGHT(prclDst) * ABS(pBltParms->pDst->Stride()), CACHE_SYNC_DISCARD);
                }
            }
        }
    }    
    
    if(pBltParms->pBrush)
    {
        if (!pBltParms->pBrush->InVideoMemory())
        {    
            if(pBltParms->pBrush->Stride()>0)
            {
                CacheRangeFlush((PBYTE)pBltParms->pBrush->Buffer(),
                    pBltParms->pBrush->Height() * ABS(pBltParms->pBrush->Stride()), CACHE_SYNC_DISCARD);     
            }
            else
            {
                CacheRangeFlush((PBYTE)pBltParms->pBrush->Buffer() - (pBltParms->pBrush->Height()-1) * ABS(pBltParms->pBrush->Stride()),
                    pBltParms->pBrush->Height() * ABS(pBltParms->pBrush->Stride()), CACHE_SYNC_DISCARD); 
            }
        }
    }    

    if(pBltParms->pMask)
    {
        if (!pBltParms->pMask->InVideoMemory())
        {    
            if(pBltParms->pMask->Stride()>0)
            {
                if(pBltParms->pMask->Height() == 0)
                {
                    CacheRangeFlush((PBYTE)pBltParms->pMask->Buffer() + pBltParms->prclMask->top * pBltParms->pMask->Stride(),
                        RECT_HEIGHT(pBltParms->prclMask) * ABS(pBltParms->pMask->Stride()), CACHE_SYNC_DISCARD);     
                }
                else
                {
                    CacheRangeFlush((PBYTE)pBltParms->pMask->Buffer(),
                        pBltParms->pMask->Height() * ABS(pBltParms->pMask->Stride()), CACHE_SYNC_DISCARD);     
                }
            }
            else
            {
                if(pBltParms->pMask->Height() == 0)
                {
                    CacheRangeFlush((PBYTE)pBltParms->pMask->Buffer() - (RECT_HEIGHT(pBltParms->prclMask)-1) * ABS(pBltParms->pMask->Stride()),
                        RECT_HEIGHT(pBltParms->prclMask) * ABS(pBltParms->pMask->Stride()), CACHE_SYNC_DISCARD);     
                }
                else
                {
                    CacheRangeFlush((PBYTE)pBltParms->pMask->Buffer() - (pBltParms->pMask->Height()-1) * ABS(pBltParms->pMask->Stride()),
                        pBltParms->pMask->Height() * ABS(pBltParms->pMask->Stride()), CACHE_SYNC_DISCARD); 
                }
            }
        }    
    }
}

#else
void
FIMG2D::CacheFlushForSurf(GPEBltParms *pBltParms, PRECTL prclSrc, PRECTL prclDst, PRECTL prclClip, G2D_ACCEL_CONTROL_ARGS m_G2DAccelArgs)
{
    if((pBltParms->pSrc) && (!m_descSrcSurface.pdwBaseaddr))
    {
        if (!pBltParms->pSrc->InVideoMemory())
        {
            if(pBltParms->pSrc->Stride()>0)
            {
                CacheFlush((PBYTE)pBltParms->pSrc->Buffer() + prclSrc->top*pBltParms->pSrc->Stride(),
                    RECT_WIDTH(prclSrc) * pBltParms->pSrc->BytesPerPixel(), RECT_HEIGHT(prclSrc), ABS(pBltParms->pSrc->Stride()), 
                    prclSrc->left * pBltParms->pSrc->BytesPerPixel(), CLEAN);
            }
            else
            {
                CacheFlush((PBYTE)pBltParms->pSrc->Buffer() - (pBltParms->pSrc->Height()-1) * ABS(pBltParms->pSrc->Stride())
                    + (pBltParms->pSrc->Height() - prclSrc->bottom) * ABS(pBltParms->pSrc->Stride()),
                    RECT_WIDTH(prclSrc) * pBltParms->pSrc->BytesPerPixel(), RECT_HEIGHT(prclSrc), ABS(pBltParms->pSrc->Stride()), 
                    prclSrc->left * pBltParms->pSrc->BytesPerPixel(), CLEAN);    
            }
        }
    }          

    if ((pBltParms->pDst) && (!m_descDstSurface.pdwBaseaddr))
    {
        if (!pBltParms->pDst->InVideoMemory() || (m_G2DAccelArgs.UseCachedVideoMemory && m_G2DAccelArgs.UseCacheFlushForVideoMemory))
        {   
            DWORD dwCache_Operation = INVALIDATE;
            if ((pBltParms->bltFlags & BLT_ALPHABLEND) && (!pBltParms->pDst->InVideoMemory()))
            {
                dwCache_Operation = CLEAN_AND_INVALIDATE;
            }
            
            if(pBltParms->pDst->Stride()>0)
            {
                if (pBltParms->pDst->IsRotate() && pBltParms->bltFlags & BLT_STRETCH)
                {
                    CacheFlush((PBYTE)pBltParms->pDst->Buffer(),
                        ABS(pBltParms->pDst->Stride()), pBltParms->pDst->Height(), ABS(pBltParms->pDst->Stride()), 0, dwCache_Operation);           
                }
                else
                {            
                    CacheFlush((PBYTE)pBltParms->pDst->Buffer() + prclDst->top * pBltParms->pDst->Stride(),
                        RECT_WIDTH(prclDst) * pBltParms->pDst->BytesPerPixel(), RECT_HEIGHT(prclDst), ABS(pBltParms->pDst->Stride()), 
                        prclDst->left * pBltParms->pDst->BytesPerPixel(), dwCache_Operation);
                }                        
            }
            else
            {
                if (pBltParms->pDst->IsRotate() && (pBltParms->bltFlags & BLT_STRETCH))
                {
                    CacheFlush((PBYTE)pBltParms->pDst->Buffer() - (pBltParms->pDst->Height()-1) * ABS(pBltParms->pDst->Stride()),
                        ABS(pBltParms->pDst->Stride()), pBltParms->pDst->Height(), ABS(pBltParms->pDst->Stride()), 0, dwCache_Operation);
                }
                else
                {            
                    CacheFlush((PBYTE)pBltParms->pDst->Buffer() - (pBltParms->pDst->Height()-1) * ABS(pBltParms->pDst->Stride())
                        + (pBltParms->pDst->Height() - prclDst->bottom) * ABS(pBltParms->pDst->Stride()),
                        RECT_WIDTH(prclDst) * pBltParms->pDst->BytesPerPixel(), RECT_HEIGHT(prclDst), ABS(pBltParms->pDst->Stride()), 
                        prclDst->left * pBltParms->pDst->BytesPerPixel(), dwCache_Operation);                        
                }                        
            }
        }
    }    
    
    if(pBltParms->pBrush)
    {
        if (!pBltParms->pBrush->InVideoMemory())
        {    
            if(pBltParms->pBrush->Stride()>0)
            {
                CacheFlush((PBYTE)pBltParms->pBrush->Buffer(),
                    ABS(pBltParms->pBrush->Stride()), pBltParms->pBrush->Height(), ABS(pBltParms->pBrush->Stride()), 0, CLEAN);     
            }
            else
            {
                CacheFlush((PBYTE)pBltParms->pBrush->Buffer() - (pBltParms->pBrush->Height()-1) * ABS(pBltParms->pBrush->Stride()),
                    ABS(pBltParms->pBrush->Stride()), pBltParms->pBrush->Height(), ABS(pBltParms->pBrush->Stride()), 0, CLEAN);
            }
        }
    }    

    if(pBltParms->pMask)
    {
        if (!pBltParms->pMask->InVideoMemory())
        {    
            if(pBltParms->pMask->Stride()>0)
            {
                if(pBltParms->pMask->Height() == 0)
                {
                    CacheFlush((PBYTE)pBltParms->pMask->Buffer() + pBltParms->prclMask->top * pBltParms->pMask->Stride(),
                        min((RECT_WIDTH(pBltParms->prclMask)/8)+1, ABS(pBltParms->pMask->Stride())), RECT_HEIGHT(pBltParms->prclMask), ABS(pBltParms->pMask->Stride()),
                        (pBltParms->prclMask->left)/8, CLEAN);                          
                }
                else
                {
                    CacheFlush((PBYTE)pBltParms->pMask->Buffer(),
                        ABS(pBltParms->pMask->Stride()), pBltParms->pMask->Height(), ABS(pBltParms->pMask->Stride()), 0,CLEAN);    
                }
            }
            else
            {
                if(pBltParms->pMask->Height() == 0)
                {
                    CacheFlush((PBYTE)pBltParms->pMask->Buffer() - (RECT_HEIGHT(pBltParms->prclMask)-1) * ABS(pBltParms->pMask->Stride()),
                        min((RECT_WIDTH(pBltParms->prclMask)/8)+1, ABS(pBltParms->pMask->Stride())), RECT_HEIGHT(pBltParms->prclMask), ABS(pBltParms->pMask->Stride()),
                        (pBltParms->prclMask->left)/8, CLEAN);
                }
                else
                {
                    CacheFlush((PBYTE)pBltParms->pMask->Buffer() - (pBltParms->pMask->Height()-1) * ABS(pBltParms->pMask->Stride()),
                        ABS(pBltParms->pMask->Stride()), pBltParms->pMask->Height(), ABS(pBltParms->pMask->Stride()), 0, CLEAN);     
                }
            }
        }    
    }
}
#endif


SCODE
FIMG2D::BitBlt(GPEBltParms *pBltParms, G2D_ACCEL_CONTROL_ARGS m_G2DControlArgs)
{
    SCODE   sReturnVal = S_OK;
    RECTL   rclDst, rclSrc, rclClip;
    DWORD   dwTopStrideStartAddr = 0;
    DWORD   dwXdirection = 0, dwYdirection = 0;

    m_G2DAccelArgs = m_G2DControlArgs;

    memset(&m_sCMD, 0, sizeof(m_sCMD));

    if(pBltParms->pSrc != NULL && pBltParms->prclSrc != NULL)
    {
        CopyRect((LPRECT)&rclSrc, (LPRECT)pBltParms->prclSrc);

        CopyRect((LPRECT)&rclDst, (LPRECT)pBltParms->prclDst);
        
        Calculate_Directions(pBltParms, &rclDst, &rclSrc);     
    }
    else
    {
        CopyRect((LPRECT)&rclSrc, NULL);
        CopyRect((LPRECT)&rclDst, (LPRECT)pBltParms->prclDst);
        Calculate_Directions(pBltParms, &rclDst, NULL);
    }
    m_descDstSurface.dwBaseaddr = ((DWORD)pBltParms->pDst->Buffer());
  
    if((pBltParms->pSrc) && (pBltParms->pSrc == pBltParms->pDst))  // OnScreen BitBlt
    {    
        if(Is_Overlapped_Rect(pBltParms, &rclDst, &rclSrc) != NO_OVERLAPPED)
        {
            RETAIL_2D_MSG(DISP_ZONE_2D, (_T("[G2D] OnScreen - Overlapped!!!!\r\n")));
            sReturnVal = S_FALSE;
            goto cleanAndReturn;                        
        }            
    }

    if (m_dwProcessType == G2D_FASTRETURN_INT)
    {
        WaitForIdleInterrupt();  
    }
    else if (m_dwProcessType == G2D_FASTRETURN_POL)
    {
        WaitForIdlePolling(G2D_POLLING_TIMEOUT_COUNT);
    }
        
    if(!SetSourceSurf(pBltParms, rclSrc))
    {
        sReturnVal = S_FALSE;
        goto cleanAndReturn;
    }

    if(!SetPatternSurf(pBltParms))
    {   
        sReturnVal = S_FALSE;
        goto cleanAndReturn;
    }

    if(!SetMaskSurf(pBltParms))
    {
        sReturnVal = S_FALSE;
        goto cleanAndReturn;
    }
    
    if(!SetDestinationSurf(pBltParms, rclDst))
    {
        sReturnVal = S_FALSE;
        goto cleanAndReturn;
    }   

    if(pBltParms->prclClip)
    {        
        CopyRect((LPRECT)&rclClip, (LPRECT)pBltParms->prclClip);

        if(pBltParms->pDst->IsRotate())
            RotateRectl(&rclClip, pBltParms->pDst);

        if(!SetClipRectl(&rclClip, rclDst))
    	{
            sReturnVal = S_FALSE;
            goto cleanAndReturn;
        }
    }

    if (pBltParms->bltFlags & BLT_STRETCH)
    {
        m_sCMD.dwStretchEn = TRUE;
    }
    
    if(pBltParms->bltFlags & BLT_ALPHABLEND)    
    {
        m_sCMD.dwAlphaBlendMode  = 1;
        g2d_wd_reg(ALPHA_REG, pBltParms->blendFunction.SourceConstantAlpha);
    }    

    g2d_wd_reg(ROTATE_REG, m_dwEnableRotate90);
    g2d_wd_reg(SRC_MSK_DIRECT_REG, (m_dwMaskDirectionY<<5 | m_dwMaskDirectionX<< 4 | m_dwSrcDirectionY<<1 | m_dwSrcDirectionX));
    g2d_wd_reg(DST_PAT_DIRECT_REG, (m_dwBrushDirectionY<<5 | m_dwBrushDirectionX<< 4 | m_dwDstDirectionY<<1 | m_dwDstDirectionX));
    g2d_wd_reg(ROP4_REG, pBltParms->rop4);
    g2d_wd_reg(BITBLT_COMMAND_REG, ( m_sCMD.dwSrcNonPreBlendMode << 22 | m_sCMD.dwAlphaBlendMode << 20 | m_sCMD.dwTransParentMode<< 12 | m_sCMD.dwCWEn << 8 | m_sCMD.dwStretchEn << 4 | m_sCMD.dwMaskEn));

    SurfCacheClear();


    CacheFlushForSurf(pBltParms, &rclSrc, &rclDst, &rclClip, m_G2DAccelArgs);

    if(!StartG2D(m_dwProcessType))
    {
        sReturnVal = S_FALSE;
        goto cleanAndReturn;
    }

    if((m_G2DAccelArgs.UseCloneBuffer) && (m_descDstSurface.pdwBaseaddr))
    {
        CopyCloneBuffer(pBltParms->pDst, m_descDstSurface, rclDst, CLONETOSURF);
    }

    RETAIL_2D_MSG(DISP_ZONE_2D,(_T("[G2D] Blitting Completed\r\n")));

    cleanAndReturn:

    if (m_G2DAccelArgs.UseCloneBuffer)
    {
        if(!ReleaseCloneBuffer())
        {
            RETAIL_2D_MSG(DISP_ZONE_ERROR,(_T("[G2D] Release Clone Buffer Fail!\n")));
        }
    }
    return sReturnVal;
}
