/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = EDDBPHNK                                       */
/*                                                                    */
/*   Description     = Display Device Driver functions supporting     */
/*                     BitBlt for SDBM20 blting between system memory */
/*                     bitmaps and VRAM                               */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DOSDEVICES
#define INCL_GRE_PALETTE
#define INCL_DDIMISC
#define INCL_ERRORS
#include <eddinclt.h>

#include <eddhcone.h>
#include <eddbextf.h>
#include <eddhtype.h>
#include <eddhmacr.h>
#include <edddtypt.h>
#include <eddbcone.h>

#ifdef PALETTE_MGR
#include <twozero.h>
#include <eddcextf.h>
#endif /* PALETTE_MGR */

#include <hwaccess.h>
#include <memman.h>

extern SHORT            softDrawInUse;
extern BITBLTPB         AIxfer;

#ifndef   _8514
extern MMReg            ShadowXGARegs;
extern HFILE            ring0_handle;
#else
extern MM8514Reg        Shadow8514Regs;
#endif

#ifdef PALETTE_MGR
extern BitmapHeader     DirectListEntry;
extern RGB2             HWPalette[HW_PAL_SIZE];
extern DDTType          DDT;
extern BOOL             fRealizeSupported;
extern PRGB2            MemoryDeviceDefaultPalette;
extern USHORT           SizeOfHWPalette;
#endif /* PALETTE_MGR */


/**********************************************************************/
/* Physical and virtual pointers to the PHUNK segment.                */
/**********************************************************************/
// @DMS ifndef these when posiible
ULONG   pPhunkPhys;
PVOID   pPhunkVirt;

/**********************************************************************/
/* Spare bitmap header for the PHUNK which can be used when the screen*/
/* is to be copied to the PHUNK and so a conversion of bitmap         */
/* dimensions will have taken place.                                  */
/**********************************************************************/
// @DMS ifndef these when posiible
BitmapHeader    PhunkBMHeader;

#ifdef PALETTE_MGR
/**********************************************************************/
/* Flag to indicate whether or not Palette conversion needs to be done*/
/* This is set by eddb_CreatePalMapping()                             */
/**********************************************************************/
BOOL    UsePaletteMapping;

/**********************************************************************/
/* Table used to store the mapping between the two palettes used by   */
/* eddb_CreatePaletteMapping and eddb_ConvertPhunk.                   */
/**********************************************************************/
BYTE    PaletteMapping[256];

/**********************************************************************/
/* These variables keep track of the current palette mapping so we    */
/* can use a simple last mapping still valid cache type scheme.       */
/* The palette pointers are PVOIDs because they may point to either   */
/* a DEVPAL (real palette manager palettes) or an array of RGBs (a    */
/* device default palette).                                           */
/**********************************************************************/
BOOL    CurrentMappingValid;
PVOID   CurrentSourcePalette;
PVOID   CurrentDestPalette;

#endif /* PALETTE_MGR */

#ifndef   _8514
FLATLOCKDATA    flatlockdata;
#endif //_8514

/**********************************************************************/
/* Creates the PHUNK and locks it down forever and ever and ever...   */
/**********************************************************************/

VOID eddb_CreatePhunk(VOID)
{
    /******************************************************************/
    /* Allocate a chunk of memory for the PHUNK.                      */
    /******************************************************************/
    pPhunkVirt = AllocateMemory(EXTENDED_PHUNK_SIZE,
                                MT_PHUNK,
                                MO_SSALLOC);

    /******************************************************************/
    /* Now we want to lock down the PHUNK                             */
    /******************************************************************/
    #ifndef   _8514
    flatlockdata.VirtualAddress = pPhunkVirt;
    flatlockdata.cMemorySize    = EXTENDED_PHUNK_SIZE;
    flatlockdata.ActionFlags    = 0x1e; /* block till ready           */
                                        /* contiguous memory          */
                                        /* below 16Mb                 */
                                        /* mark as dirty              */
                                        /* long term lock             */
    FlatLock(&flatlockdata);

    pPhunkPhys = flatlockdata.PhysicalAddress;
    #else
    // @DMS there isnt any physical address for 8514
    // since we cant address sytem memory with the Blt Engine.
    pPhunkPhys = NULL;
    #endif
    /******************************************************************/
    /* Dont use all of allocated memory for PHUNK so that there are   */
    /* spare bytes at each end. This allows addressing off the ends   */
    /* of the bitmap when bits must be shifted for bitblts where the  */
    /* source and destination bits of pels are not aligned.           */
    /******************************************************************/
    pPhunkPhys += END_BYTES_PHUNK_OFFSET;
    (PBYTE)pPhunkVirt += END_BYTES_PHUNK_OFFSET;

    /******************************************************************/
    /* Now we want to initialise the PHUNK bitmap header.             */
    /******************************************************************/
    PhunkBMHeader.Bitmap = pPhunkVirt;
    PhunkBMHeader.BMPhys = pPhunkPhys;
}

#ifdef PALETTE_MGR

VOID eddb_CreatePalMapping(PDC   pdcSrc)
{
    /******************************************************************/
    /* This function is called by eddb_BitBlt and sets up the palette */
    /* conversion table (PalettMapping) to be used by                 */
    /* eddb_ConvertPhunk. UsePaletteMapping is set to FALSE if the    */
    /* mapping is the identity mapping (otherwise it is set to TRUE). */
    /* The palettes to be used are obtained from pdc (for the         */
    /* destination) and pdcSrc (for the source). If pdcSrc is         */
    /* NULL then we must assume that we are using the same palette as */
    /* the destination DC.                                            */
    /*                                                                */
    /* The code must deal with Logical Color Tables (LCTs) as well as */
    /* palettes, and must be able to convert between memory/memory,   */
    /* memory/screen, and screen/memory. The case of screen/screen    */
    /* is considered as the identity mapping (even if the DCs are not */
    /* the same).                                                     */
    /*                                                                */
    /* As a quick reminder of what the pels in each case represent:   */
    /*                                                                */
    /* Screen pels are physical indexes into the Hardware Palette     */
    /* whether we are dealing with a DC which is using a palette or   */
    /* a LCT.                                                         */
    /*                                                                */
    /* Memory bitmap pels are logical indexes into a Palette if we are*/
    /* dealing with a DC which is using a Palette, or physical indexes*/
    /* into the device default palette if we are dealing with a DC    */
    /* which is using a LCT, or physical indexes into the HW palette  */
    /* if we are dealing with a DC which is using a RLCT (realizable  */
    /* LCT).                                                          */
    /******************************************************************/

    /******************************************************************/
    /* Local constants - note that we can add the devices (SCREEN and */
    /* MEMORY) to the types (PALETTE, LCT and RLCT) without loosing   */
    /* information.                                                   */
    /******************************************************************/
    #define     SCREEN  10
    #define     MEMORY  20
    #define     PALETTE 1
    #define     LCT     2
    #define     RLCT    3

    /*******************/
    /* Local variables */
    /*******************/
    ULONG       SourceType;
    ULONG       DestType;
    ULONG       SourceDevice;
    ULONG       DestDevice;
    ULONG       index;
    PRGB2       pSourceDeviceDefaultPalette;

    /******************************************************************/
    /* Decide where the source is coming from...                      */
    /******************************************************************/
    if (pdcSrc == NULL)
    {
        /**************************************************************/
        /* We have no source DC so we must assume that we are using   */
        /* a bitmap (in memory) that is of the same type as the       */
        /* destination. (Note that we set up a pointer to the device  */
        /* default palette and the code later always uses this rether */
        /* than the value in the pdcSrc. We have to do this because   */
        /* in the destination may be an LCT on the screen and so      */
        /* could be using a different device default palette.  Since  */
        /* we set up pdcSrc to be pdc here then we would loose that   */
        /* information and would not convert when we had to.)         */
        /**************************************************************/
        SourceDevice = MEMORY;
        pSourceDeviceDefaultPalette = MemoryDeviceDefaultPalette;
        pdcSrc = pdc;

        if (pdc->DCIColFormat == LCOLF_PALETTE)
        {
            SourceType = PALETTE;
        }
        else if (fRealizeSupported && (pdc->DCIColStatus & LCOL_REALIZABLE))
        {
            SourceType = RLCT;
        }
        else
        {
            SourceType = LCT;
        }
    }
    else
    {
        /**************************************************************/
        /* We do have a source DC so we must use it to work out all   */
        /* we need to know about the source to decide how to go about */
        /* the operation.                                             */
        /**************************************************************/
        pSourceDeviceDefaultPalette = pdcSrc->DCIDeviceDefaultPalette;

        if (pdcSrc->DCIDCType == OD_DIRECT)
        {
            SourceDevice = SCREEN;
        }
        else
        {
            SourceDevice = MEMORY;
        }

        if (pdcSrc->DCIColFormat == LCOLF_PALETTE)
        {
            SourceType = PALETTE;
        }
        else if (fRealizeSupported && (pdcSrc->DCIColStatus & LCOL_REALIZABLE))
        {
            SourceType = RLCT;
        }
        else
        {
            SourceType = LCT;
        }
    }


    /******************************************************************/
    /* ...and where the destination is going to.                      */
    /******************************************************************/
    if (pdc->DCIDCType == OD_DIRECT)
    {
        DestDevice = SCREEN;
    }
    else
    {
        DestDevice = MEMORY;
    }

    if (pdc->DCIColFormat == LCOLF_PALETTE)
    {
        DestType = PALETTE;
    }
    else if (fRealizeSupported && (pdc->DCIColStatus & LCOL_REALIZABLE))
    {
        DestType = RLCT;
    }
    else
    {
        DestType = LCT;
    }

    /******************************************************************/
    /* Do some tests now to see if we are going to need to bother     */
    /* using a PaletteMapping. If both the source and the destination */
    /* are the screen or either are RLCTs then we use a one to one    */
    /* mapping.  If both the source and the destination are using the */
    /* same palette then there is no need to do any conversion if     */
    /* they are using the same device type (screen contains indexes   */
    /* into the HW palette, memory contains indexes into the palette  */
    /* manager palette).  If both the source and the destination are  */
    /* using an LCT which is mapped onto the same device default      */
    /* palette then we do not need to do any conversion.              */
    /******************************************************************/
    if (   (SourceType == RLCT)
        || (DestType == RLCT)
        || ( (SourceDevice == SCREEN) && (DestDevice == SCREEN) )

        || ( (SourceType == PALETTE) && (DestType == PALETTE)
             && (pdcSrc->Palette == pdc->Palette)
             && (SourceDevice == DestDevice) )

        || ( (SourceType == LCT) && (DestType == LCT)
             && ( pSourceDeviceDefaultPalette ==
                  pdc->DCIDeviceDefaultPalette) )
       )
    {
        UsePaletteMapping = FALSE;
        return;
    }


    /******************************************************************/
    /* We have to use a palette mapping but with a bit (or a lot) of  */
    /* luck the current palette mapping will be the same as the       */
    /* mapping we want to use so there will be no need to recreate    */
    /* the palette mapping.  CurrentMappingValid is always set to     */
    /* FALSE whenever either of the "palettes" (HW palette / LCTs /   */
    /* palman palettes) envolved in the mapping get altered in anyway.*/
    /******************************************************************/
    if ( CurrentMappingValid

         &&
          (  ((SourceDevice == SCREEN) && (CurrentSourcePalette == FNULL))
           ||
             ((SourceType == PALETTE) && (SourceDevice != SCREEN)
                && (CurrentSourcePalette == pdcSrc->Palette))
           ||
             ((SourceType == LCT) &&
              (CurrentSourcePalette == pSourceDeviceDefaultPalette))
          )

         &&
          (  ((DestType == PALETTE) && (CurrentDestPalette == pdc->Palette))
           ||
             ((DestType == LCT) &&
                (CurrentDestPalette == pdc->DCIDeviceDefaultPalette))
          )
       )
    {
        /**************************************************************/
        /* We can use the current palette-palette mapping.            */
        /**************************************************************/
        UsePaletteMapping = TRUE;
        return;
    }


    /******************************************************************/
    /* Now for each case lets loop through the palettes and set up    */
    /* each entry in the PaletteMapping table.                        */
    /******************************************************************/
    switch (SourceType+SourceDevice)
    {
        case PALETTE+SCREEN:
        case LCT+SCREEN:
            switch (DestType+DestDevice)
            {
                case PALETTE+SCREEN:
                case RLCT+SCREEN:
                case RLCT+MEMORY:
                case LCT+SCREEN:
#ifdef FIREWALLS
                    haltproc();
#endif /* FIREWALLS */
                    break;

                case PALETTE+MEMORY:
                    for (index = 0; index < 256; index++)
                    {
                        PaletteMapping[index] = (BYTE)
                           NearestPaletteIndex(HWPalette[index]);
                    }
                    CurrentDestPalette = pdc->Palette;
                    break;

                case LCT+MEMORY:
                    for (index = 0; index < 256 ; index++)
                    {
                        PaletteMapping[index] = (BYTE)
                           NearestMemoryDefaultPhysicalIndex(HWPalette[index]);
                    }
                    CurrentDestPalette = pdc->DCIDeviceDefaultPalette;
                    break;
            }
            CurrentSourcePalette = NULL;
            break;

        case PALETTE+MEMORY:
            switch (DestType+DestDevice)
            {
                case RLCT+SCREEN:
                case RLCT+MEMORY:
#ifdef FIREWALLS
                    haltproc();
#endif /* FIREWALLS */
                    break;

                case PALETTE+SCREEN:
                    for (index = 0;
                         index < pdcSrc->Palette->usCountStored;
                         index++)
                    {
                        PaletteMapping[index] = (BYTE)
                            pdc->Palette->entries[
                                    NearestPaletteIndex(
                                    pdcSrc->Palette->entries[index].rgb)
                                ].bCurrent;
                    }
                    while (index < 256)
                    {
                        PaletteMapping[index++] = (BYTE)0;
                    }
                    CurrentDestPalette = pdc->Palette;  // Defect 62735
                    break;

                case PALETTE+MEMORY:
                    for (index = 0;
                         index < pdcSrc->Palette->usCountStored;
                         index++)
                    {
                        PaletteMapping[index] = (BYTE)
                                NearestPaletteIndex(
                                pdcSrc->Palette->entries[index].rgb);
                    }
                    while (index < 256)
                    {
                        PaletteMapping[index++] = (BYTE)0;
                    }
                    CurrentDestPalette = pdc->Palette;
                    break;

                case LCT+SCREEN:
                    for (index = 0;
                         index < pdcSrc->Palette->usCountStored;
                         index++)
                    {
                        PaletteMapping[index] = (BYTE)
                                NearestDirectDefaultPhysicalIndex(
                                pdcSrc->Palette->entries[index].rgb);
                    }
                    while (index < 256)
                    {
                        PaletteMapping[index++] = (BYTE)0;
                    }
                    CurrentDestPalette = pdc->DCIDeviceDefaultPalette;
                    break;

                case LCT+MEMORY:
                    for (index = 0;
                         index < pdcSrc->Palette->usCountStored;
                         index++)
                    {
                        PaletteMapping[index] = (BYTE)
                                NearestMemoryDefaultPhysicalIndex(
                                pdcSrc->Palette->entries[index].rgb);
                    }
                    while (index < 256)
                    {
                        PaletteMapping[index++] = (BYTE)0;
                    }
                    CurrentDestPalette = pdc->DCIDeviceDefaultPalette;
                    break;
            }
            CurrentSourcePalette = pdcSrc->Palette;
            break;

        case LCT+MEMORY:
            switch (DestType+DestDevice)
            {
                case RLCT+SCREEN:
                case RLCT+MEMORY:
                case LCT+MEMORY:
#ifdef FIREWALLS
                    haltproc();
#endif /* FIREWALLS */
                    break;

                case PALETTE+SCREEN:
                    for (index = 0; index < 256 ; index++)
                    {
                        PaletteMapping[index] = (BYTE)
                            pdc->Palette->entries[
                                NearestPaletteIndex(
                                MemoryDeviceDefaultRGB2(index))
                            ].bCurrent;
                    }
                    CurrentDestPalette = pdc->Palette;   // Defect 62735
                    break;

                case PALETTE+MEMORY:
                    for (index = 0; index < 256 ; index++)
                    {
                        PaletteMapping[index] = (BYTE)
                                NearestPaletteIndex(
                                MemoryDeviceDefaultRGB2(index));
                    }
                    CurrentDestPalette = pdc->Palette;
                    break;

                case LCT+SCREEN:
                    for (index = 0; index < 256 ; index++)
                    {
                        PaletteMapping[index] = (BYTE)
                                NearestDirectDefaultPhysicalIndex(
                                MemoryDeviceDefaultRGB2(index));
                    }
                    CurrentDestPalette = pdc->DCIDeviceDefaultPalette;
                    break;
            }
            CurrentSourcePalette = pSourceDeviceDefaultPalette;
            break;

        case RLCT+SCREEN:
        case RLCT+MEMORY:
#ifdef FIREWALLS
            haltproc();
#endif /* FIREWALLS */
            break;
    }

    /******************************************************************/
    /* Set the CurrentMappingValid flag to indicate that the current  */
    /* mapping is valid. This will be invalidated by a call to either */
    /* HWPaletteChanged or ChangedPalette or ChangedColorTable.       */
    /******************************************************************/
    CurrentMappingValid = TRUE;

    /******************************************************************/
    /* And last but not least we must set UsePaletteMapping.          */
    /******************************************************************/
    UsePaletteMapping = TRUE;
}

#endif /* PALETTE_MGR */
