/*////////////////////////////////////////////////////////////////////////
//                                                                      //
//              INTEL CORPORATION PROPRIETARY INFORMATION               //
//                                                                      //
//      This software is supplied under the terms of a license          //
//      agreement or nondisclosure agreement with Intel Corporation     //
//      and may not be copied or disclosed except in accordance         //
//      with the terms of that agreement.                               //
//                                                                      //
////////////////////////////////////////////////////////////////////////*/


/*******************************************************************
 *
 *        FILE:                 dcisamp.c
 *
 *    DESCRIPTION:      DCI entry points for sample disp. driver helper DLL
 *
 *    AUTHOR:           Blake Bender, Davis W. Frank
 *
 *        DATE:                 1/17/94
 *
 *******************************************************************/

#include <windows.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <stdlib.h>
#include <dciddi.h>
#include "dcihdw.h"
#include "debug.h"

/* Globals */
extern BOOL fHardwareSupport;

/*
 ** DCICreatePrimarySurface()
 *
 *  Parameters:     lParam1             
 *                      FAR pointer to DCICREATEINPUT
 *                  lParam2         
 *                      FAR pointer to FAR pointer to DCI Provider's return
 *                      structure
 *
 *  Description:    Function to acquire on-screen display surface in the current 
 *                  video mode. 
 *
 *  Returns:        DCI_OK on success, or an error code on failure.
 *
 *  Side Effects:   Allocates space for a DCIPRIMARY + all instance data and 
 *                  returns the structure off of lParam2.  All fields of 
 *                  DCIPRIMARY structure set to on screen "Primary" surface
 *                               
 */
int     FAR PASCAL _loadds DCICreatePrimarySurface( LPVOID lParam1, LPVOID lParam2 )
{
    LPDCICREATEINPUT        lpInput = (LPDCICREATEINPUT)lParam1;
    LPPRIMESURFINFO FAR     *lpTmp  = (LPPRIMESURFINFO FAR *)(LPVOID)lParam2;
    LPPRIMESURFINFO         pinst;
    COLORSUPPORT            csCurrentFmt = NoColorSupport;
    int                     rval = DCI_OK;
    DWORD                   dwEndOffset, x = 0L, y = 0L;
    DWORD                   dwCompression, dwMask[3];
    WORD                    wBPP, wStride;
    HGLOBAL                 hTmp;
    
        
    ODS("DCICreatePrimarySurface\n");

	    
    if (!lpInput)
        return DCI_FAIL_INVALIDSURFACE;

    if (lpInput->cmd.dwVersion != DCI_VERSION)
        return DCI_FAIL_UNSUPPORTEDVERSION;

    /* Check to see if hardware is supported and 
     * get data format
     */
    if (fHardwareSupport)
        csCurrentFmt = VidQueryColorSupport();
    else
        return DCI_FAIL_UNSUPPORTED;

    /* fill knowns about this format */
    switch(csCurrentFmt)
    {
        case RGB8_CLUT:
            dwCompression = BI_RGB;
            wBPP          = 8;
            break;
        case RGB16_555:
            dwCompression = BI_RGB;
            wBPP          = 16;
            break;
        case RGB16_565:
            dwCompression = BI_BITFIELDS;
            wBPP          = 16;
            dwMask[0]     = 0x0000f800;
            dwMask[1]     = 0x000007e0;
            dwMask[2]     = 0x0000001f;
            break;
        default:
            rval = DCI_ERR_CURRENTLYNOTAVAIL; /* not in a disp. mode we like */
            break;
    }

    /* return if status is NOT DCI_OK */
    if (rval != DCI_OK)
        return rval;

    /* DCI is supported */

    /* alloc space for a PRIMESURFINFO -- DCIPRIMARY + instance data */
    hTmp = GlobalAlloc(GHND | GMEM_SHARE, sizeof(PRIMESURFINFO));
    /* fail if allocation fails */
    if (!hTmp)
        return DCI_ERR_OUTOFMEMORY;

    /* store FAR pointer "into" lParam2 (lpTmp) */          
    *lpTmp            = (LPVOID) GlobalLock(hTmp);
    pinst             = (LPPRIMESURFINFO) *lpTmp;
    pinst->hPrimeInfo = hTmp;

    /* Get Selector and Offset for screen (0,0) and store them in pinst */ 
    /* NOTE: dwEndOffset is not used and wStride is converted later     */
    VidGetDevMemAccess (x, y, 
                        (LPWORD)&(pinst->Surface.wSelSurface), 
                        (LPDWORD)&(pinst->Surface.dwOffSurface), 
                        (LPDWORD)&dwEndOffset, 
                        (LPWORD)&(wStride));

    /* Fill DCISURFACEINFO in DCIPRIMARY for return to DCI Manager */
    pinst->Surface.dwSize         = sizeof(PRIMESURFINFO);
    pinst->Surface.dwDCICaps      = DCI_PRIMARY | DCI_VISIBLE;
    pinst->Surface.dwCompression  = dwCompression;
    pinst->Surface.dwBitCount     = (DWORD)wBPP;                                                                                                                
    pinst->Surface.dwMask[0]      = dwMask[0];
    pinst->Surface.dwMask[1]      = dwMask[1];
    pinst->Surface.dwMask[2]      = dwMask[2];                                  
    pinst->Surface.dwWidth        = (DWORD) GetSystemMetrics(SM_CXSCREEN);
    pinst->Surface.dwHeight       = (DWORD) GetSystemMetrics(SM_CYSCREEN);
    pinst->Surface.lStride        = (LONG) wStride;
    pinst->Surface.BeginAccess    = BeginAccess;
    pinst->Surface.EndAccess      = EndAccess;
    pinst->Surface.DestroySurface = DestroySurface;
    

    /* return status code, DCI_OK to DCI Manager */
    return rval;
}


/*
 ** DCIEnumSurface
 *
 *  Parameters:         lParam1         FAR pointer to DCIENUMINPUT
 *                                      lParam2         NULL, ignored
 *
 *  Description:        The DCI Manager calls this function in order to determine 
 *                      which data formats the DCI Provider supports.  
 *                      DCIEnumSurface calls the supplied callback once for each 
 *                      data format is supported.
 *
 *  Returns:            DCI_OK on success, or an error code on failure.
 *
 *  Side Effects:       None.
 */
int FAR PASCAL _loadds DCIEnumSurface( LPVOID lParam1,LPVOID lParam2 )
 {
    COLORSUPPORT    csCurrentFmt = NoColorSupport;
    LPDCIENUMINPUT  lpEnumInput  = (LPDCIENUMINPUT)lParam1;
    DCISURFACEINFO  dciInfo;


    ODS("DCIEnumSurface\n");
    
    /* check for NULL input.  Fail bogus call. */
    if (!lpEnumInput)
        return DCI_FAIL_INVALIDSURFACE;

    /* if hardware is supported, get data format
     * else fail and return
     */
    if (fHardwareSupport)
        csCurrentFmt = VidQueryColorSupport();  
    else
        return DCI_FAIL_UNSUPPORTED;

    /* fill DCISURFACEINFO based on COLORSUPPORT */
    if (csCurrentFmt == RGB8_CLUT)
    {
        dciInfo.dwBitCount    = 8;
        dciInfo.dwCompression = BI_RGB;
        dciInfo.dwMask[0]     = 0L;
        dciInfo.dwMask[1]     = 0L;
        dciInfo.dwMask[2]     = 0L;
    }
    else if ((csCurrentFmt == RGB16_555) ||
             (csCurrentFmt == RGB16_565))
    {
        /* 
         * This is a hack to show support for the Indeo intermediate format, 
         * Fourcc 'IF09'.  We simply tell the DCI client we have a surface of
         * this format, and convert it to 4:2:2 and blast it to the frame 
         * buffer in RGB555 or 565 mode.  Not pretty, but if you have a 4:2:2
         * frame buffer, this is almost all you'll need for Indeo.
         */
        dciInfo.dwBitCount    = 9;
        dciInfo.dwCompression = BI_IF09;
        dciInfo.dwMask[0]     = 0L;
        dciInfo.dwMask[1]     = 0L;
        dciInfo.dwMask[2]     = 0L;
    }

    /* Set width, height to Src rect -- the size of surface Client is requesting. */
    dciInfo.dwWidth  = (DWORD)(lpEnumInput->rSrc.right - lpEnumInput->rSrc.left);
    dciInfo.dwHeight = (DWORD)(lpEnumInput->rSrc.bottom - lpEnumInput->rSrc.top);
    
    if ((!dciInfo.dwWidth)&&(!dciInfo.dwHeight))
    {
        /* empty rectangles.  This means "tell me what your biggest surface is".
         * We set to a default of 640 x 480 for convenience only, a "real" DCI
         * provider should set these to the max. allowable offscreen surface.
         */
        dciInfo.dwWidth = 640;
        dciInfo.dwHeight = 480;
    }

    /* Fill dwDCICaps for the requested stretch/surface */
    dciInfo.dwDCICaps = DCI_OFFSCREEN | DCI_CAN_STRETCHXY;
    
    dciInfo.dwSize = sizeof(OFFINSTINFO);
    
    /* only call EnumCallback if Dest BMP is less than 1MB */
    if (dciInfo.dwWidth * dciInfo.dwHeight * (dciInfo.dwBitCount/8) > 0x100000)
        return DCI_ERR_TOOBIGSIZE;      /* fail = zero callbacks */			
    
    (lpEnumInput->EnumCallback)((LPDCISURFACEINFO)&dciInfo, lpEnumInput->lpContext);

    return DCI_OK;
}

/*
 ** DCICreateOffScreenSurface()
 *
 *  Parameters:         lParam1         
 *                          FAR pointer to DCICREATEINPUT
 *                      lParam2         
 *                          FAR pointer to FAR pointer to DCI Provider's return
 *                          structure
 *
 *  Description:        Function to acquire off-screen display surface in the 
 *                      current video mode. 
 *
 *  Returns:            DCI_OK on success, or an error code on failure.  
 *
 *  Side Effects:       Allocates space for a DCIOFFSCREEN + all instance 
 *                      data and returns the structure off of lParam2.  All
 *                      fields of DCIOFFSCREEN structure set to off screen
 *                      surface (an allocated system buffer) to which the
 *                      DCIClient writes. DrawOff callback will handle
 *                      stretching this surface to the screen
 *                                
 */
int FAR PASCAL _loadds DCICreateOffscreenSurface( LPVOID lParam1, LPVOID lParam2 )
{
    LPDCICREATEINPUT    lpInput = (LPDCICREATEINPUT)lParam1;
    LPOFFINSTINFO  FAR *lpSurf  = (LPOFFINSTINFO FAR *)(LPVOID)lParam2;
    LPVOID              lpTmp, lpTmp2;
    COLORSUPPORT        csCurrentFmt = NoColorSupport;
    LPOFFINSTINFO       oinst;
    HGLOBAL             hSurf;
    int                 rval = DCI_OK;  
    WORD                wStride;
    DWORD               x = 0L,
                        y = 0L,
                        dwOffSize,
                        dwEndOffset;

    ODS("DCICreateOffScreenSurface\n");
 
    /* check for bogus input pointer */
    if (!lpInput)
        return DCI_FAIL_INVALIDSURFACE;

    /* if hardware is supported, get data format
     * else fail and return
     */
    if (fHardwareSupport)
        csCurrentFmt = VidQueryColorSupport();
    else
        return DCI_FAIL_UNSUPPORTED;

    /* alloc space for OFFINSTINFO */
    hSurf = GlobalAlloc(GHND | GMEM_SHARE, sizeof(OFFINSTINFO));
    /* fail if allocation fails */
    if (!hSurf)
        return DCI_ERR_OUTOFMEMORY;

    *lpSurf = (LPOFFINSTINFO) GlobalLock(hSurf);
    oinst = (LPOFFINSTINFO)(*lpSurf);
    
    /* Get Selector and Offset for screen (0,0) and store them in pinst */ 
    /* NOTE: dwEndOffset is not used and wStride is converted later     */
    VidGetDevMemAccess (x, y, 
                        (LPWORD)&(oinst->wSelScrn), 
                        (LPDWORD)&(oinst->dwOffScrn), 
                        (LPDWORD)&dwEndOffset, 
                        (LPWORD)&(wStride));
                        
    oinst->lStrideScrn = (LONG) wStride;
    
    /* Fill DCIOFFSCREEN return struct */           
    oinst->OffSurface.dciInfo.dwSize          = sizeof(OFFINSTINFO);
    oinst->OffSurface.dciInfo.dwDCICaps       = DCI_OFFSCREEN | DCI_CAN_STRETCHXY;
    oinst->OffSurface.dciInfo.dwCompression   = lpInput->dwCompression;
    oinst->OffSurface.dciInfo.dwMask[0]       = 0L;
    oinst->OffSurface.dciInfo.dwMask[1]       = 0L;
    oinst->OffSurface.dciInfo.dwMask[2]       = 0L;
    oinst->OffSurface.dciInfo.dwWidth         = lpInput->dwWidth;
    oinst->OffSurface.dciInfo.dwHeight        = lpInput->dwHeight;
    oinst->OffSurface.dciInfo.dwBitCount      = (lpInput->dwCompression) ? 9: 8;
    oinst->OffSurface.dciInfo.BeginAccess     = BeginAccessOff;
    oinst->OffSurface.dciInfo.EndAccess       = EndAccessOff;
    oinst->OffSurface.dciInfo.DestroySurface  = DestroySurfaceOff;   
    oinst->OffSurface.SetDestination          = SetDestinationOff;
    oinst->OffSurface.SetClipList             = SetCliplistOff;
    oinst->OffSurface.Draw                    = DrawOff;
            
    /* calc surface size */
    if (lpInput->dwCompression)    
        dwOffSize = (labs(lpInput->dwWidth) *
            labs(lpInput->dwHeight) * 5L) / 4L; 
    else
        dwOffSize = (labs(lpInput->dwWidth) *
            labs(lpInput->dwHeight)); 
    
    /* alloc proper size for extended surface */
    oinst->hOffSurf = GlobalAlloc(GHND | GMEM_SHARE, dwOffSize);
    if (!oinst->hOffSurf)
    {
        GlobalUnlock(hSurf);
        GlobalFree(hSurf);
		*lpSurf = NULL;
        return DCI_ERR_OUTOFMEMORY;
    }
    lpTmp = (LPVOID) GlobalLock(oinst->hOffSurf);

    /* succesful allocation, assign selector, offset fields of SURFACEINFO */
    oinst->OffSurface.dciInfo.wSelSurface  = SELECTOROF(lpTmp);
    oinst->OffSurface.dciInfo.dwOffSurface = OFFSETOF(lpTmp);
    oinst->OffSurface.dciInfo.lStride      = lpInput->dwWidth;
    
    /* alloc 1MB for clipblit buffer */
    oinst->hCBlit = GlobalAlloc(GHND | GMEM_SHARE, 0x100000);
    if (!oinst->hCBlit)
    {
        GlobalUnlock(oinst->hOffSurf);
        GlobalFree(oinst->hOffSurf);
        GlobalUnlock(hSurf);
        GlobalFree(hSurf);
		*lpSurf = NULL;
        return DCI_ERR_OUTOFMEMORY;
    }
    lpTmp2 = (LPVOID) GlobalLock(oinst->hCBlit);

    /* if successful assign sel & off fields in exinst */
    oinst->wSelCBlit  = SELECTOROF(lpTmp2);
    oinst->dwOffCBlit = OFFSETOF(lpTmp2);
    
    /* allocate memory to handle clipping */
    oinst->hClipInfo = GlobalAlloc(GHND | GMEM_SHARE, 512*sizeof(CLIPRECTINFO));
    if (!oinst->hClipInfo)
    {
        GlobalUnlock(oinst->hCBlit);
        GlobalFree(oinst->hCBlit);
        GlobalUnlock(oinst->hOffSurf);
        GlobalFree(oinst->hOffSurf);
        GlobalUnlock(hSurf);
        GlobalFree(hSurf);
		*lpSurf = NULL;
        return DCI_ERR_OUTOFMEMORY;
    }
    oinst->lpClipInfo = (LPCLIPRECTINFO)GlobalLock(oinst->hClipInfo);
    
    oinst->fClipState = CS_NOCLIP;
    return rval;
}

/*--------------------------surface Callback functions---------------------------*/
/*
 ** BeginAccess
 *
 *  Parameters:         LPVOID lpSurface 
 *                          actually a FAR pointer to a PRIMESURFINFO structure
 *                          (the one passed back from DCICreatePrimarySurface).
 *                      LPRECT r
 *                          FAR pointer to RECT describing, in screen 
 *                          coordinates, the destination rectangle for this 
 *                          Surface.  This is passed so the cursor can be 
 *                          excluded from this screen rectangle
 *
 *  Description:        Called to let the driver know that drawing to the screen
 *                      is about to occur.
 *
 *  Returns:            DCI_STATUS flag to indicate changes to the 
 *                      DCISURFACEINFO, if any
 *
 *  Side Effects:   DCI Client knows that Surface is accessible
 */
DCIRVAL CALLBACK _loadds BeginAccess(LPVOID lpSurface, LPRECT r)
{
    ODS("BeginAccess\n");

    /* we only support boards with a H/W cursor in the sample driver, so do
     * nothing.
     */
    return DCI_OK;
}


/*
 ** EndAccess
 *
 *  Parameters:         LPVOID lpSurface -- actually a FAR pointer to a 
 *                          PRIMESURFINFO structure (the one passed back from 
 *                          DCICreatePrimarySurface).
 *
 *  Description:        Called to let the driver know that drawing to the screen 
 *                      is done.  Used in offscreen cases to let driver know to
 *                      transfer data to onscreen memory.
 *
 *  Returns:            none.
 *
 *  Side Effects:       none.
 */
void CALLBACK _loadds EndAccess(LPVOID lpSurface)
{
    ODS("EndAccess\n");

    return;
}

/*
 ** DestroySurface
 *
 *  Parameters:     LPVOID lpSurface -- actually a FAR pointer to a 
 *                  PRIMESURFINFO structure (the one passed back from 
 *                  DCICreatePrimarySurface).
 *
 *  Description:    Sent to DCI surface provider to tell it to free up any 
 *                  memory associated with this surface, and close down the 
 *                  surface.
 *
 *  Returns:        none.
 *
 *  Side Effects:   Frees memory associated with surface.
 */
void CALLBACK _loadds DestroySurface(LPVOID lpSurface)
{
    LPPRIMESURFINFO  pinst = (LPPRIMESURFINFO)lpSurface;


    ODS("DestroySurface\n");
    
    /* don't want to try to free NULL pointer */
    if (pinst)
    {
        GlobalUnlock(pinst->hPrimeInfo);
        GlobalFree(pinst->hPrimeInfo);
    }
    return; 
}       
