/******************************Module*Header*******************************\
* Module Name: DdHmgr.h
*
* This file contains all the prototypes for the DirectDraw handle mangager.
*
* Added header: 30-Apr-1999 16:31:46
* Author: Lindsay Steventon (linstev)
*
* Copyright (c) 1999 Microsoft Corporation
\**************************************************************************/

// <--full unique-->
// +--------+------+----------------+
// | unique | type |     index      |
// +--------+------+----------------+
//
// TYPE       - types used by DDRAW & D3D
//
// UNIQUE     - bits that are incremented for each instance of the handle
// FULLUNIQUE - bits used for comparing identical handles.  This includes the TYPE
//
// INDEX      - index into server side handle table
//

#define DD_TABLESIZE_DELTA ((PAGE_SIZE*4) / sizeof(DD_ENTRY))   // 4 pages of entries each time

#define DD_DEF_TYPE         0
#define DD_DIRECTDRAW_TYPE  1
#define DD_SURFACE_TYPE     2
#define D3D_HANDLE_TYPE     3
#define DD_VIDEOPORT_TYPE   4
#define DD_MOTIONCOMP_TYPE  5
#define DD_MAX_TYPE         5

#define DD_INDEX_BITS      21   // 2^21 ~ 2 million handles
#define DD_TYPE_BITS        3   // 2^3  = 8, we only need 6
#define DD_UNIQUE_BITS      8   // identifies each new handle
#define DD_NONINDEX_BITS    (32 - DD_INDEX_BITS)

#define DD_INDEX_SHIFT      0
#define DD_TYPE_SHIFT       (DD_INDEX_BITS)
#define DD_UNIQUE_SHIFT     (DD_TYPE_SHIFT + DD_TYPE_BITS)

// MASKS contain the bits of the handle used for the paricular field

#define DD_NONINDEX_MASK(shift,cbits)  ( ((1 << (cbits)) - 1)  << (shift) )

#define DD_INDEX_MASK       ((1 << DD_INDEX_BITS) - 1)
#define DD_TYPE_MASK        (DD_NONINDEX_MASK(DD_TYPE_SHIFT, DD_TYPE_BITS))
#define DD_UNIQUE_MASK      (DD_NONINDEX_MASK(DD_UNIQUE_SHIFT, DD_UNIQUE_BITS))
#define DD_FULLUNIQUE_MASK  (DD_UNIQUE_MASK | DD_TYPE_MASK)

#define DD_MAKE_HMGR_HANDLE(Index,Unique) LongToHandle(((((LONG) Unique) << DD_INDEX_BITS) | ((LONG) Index)))

// NOTE that DD_UNIQUE_INCREMENT is based on the uniqueness being a short, not a full handle

#define DD_UNIQUE_INCREMENT (1 << (DD_UNIQUE_SHIFT - DD_INDEX_BITS))

#define DdHmgIfromH(h)      (ULONG)((ULONG_PTR)(h) & DD_INDEX_MASK)
#define DdHmgUfromH(h)      ((USHORT) (((ULONG_PTR)(h) & DD_FULLUNIQUE_MASK) >> DD_TYPE_SHIFT))
#define DdHmgObjtype(h)     ((DD_OBJTYPE)(((ULONG_PTR)(h) & DD_TYPE_MASK)    >> DD_TYPE_SHIFT))

// given a usUnique and a type, modify it to contain a new type

#define DD_USUNIQUE(u,t) (USHORT)((u & ((ULONG)DD_UNIQUE_MASK >> (ULONG)DD_INDEX_BITS)) | \
                                  (t << (DD_TYPE_SHIFT - DD_INDEX_BITS)))

#define DD_MAX_HANDLE_COUNT    (1 << (32 - DD_NONINDEX_BITS))
#define DD_HMGR_HANDLE_BASE    1

ULONG   FASTCALL DdHmgQueryLock(HDD_OBJ hobj);
BOOL             DdHmgCreate();
BOOL             DdHmgDestroy();
BOOL             DdHmgCloseProcess(W32PID W32Pid);
HDD_OBJ          DdHmgAlloc(ULONGSIZE_T,DD_OBJTYPE,USHORT);
VOID             DdHmgFree(HDD_OBJ);
VOID             DdFreeObject(PVOID pvFree, ULONG ulType);
PDD_OBJ FASTCALL DdHmgLock(HDD_OBJ,DD_OBJTYPE,BOOL);
PDD_OBJ FASTCALL DdHmgNextObjt(HDD_OBJ hobj, DD_OBJTYPE objt);
PVOID            DdHmgRemoveObject(HDD_OBJ,LONG,LONG,BOOL,DD_OBJTYPE);
VOID             DdHmgAcquireHmgrSemaphore();
VOID             DdHmgReleaseHmgrSemaphore();

// DirectDraw Handle Manager data.

extern ULONG          gcSizeDdHmgr;
extern DD_ENTRY      *gpentDdHmgr;
extern HDD_OBJ        ghFreeDdHmgr;
extern ULONG          gcMaxDdHmgr;
extern PLARGE_INTEGER gpLockShortDelay;

/*********************************MACRO************************************\
*  INC_EXCLUSIVE_REF_CNT - increment object's exclusive reference count
*  DEC_EXCLUSIVE_REF_CNT - decrement object's exclusive reference count
*
*  Note that the InterlockedIncrement/Decrement treats the cExclusiveLock
*  as a ULONG. cExclusiveLock is declared as a USHORT and the increment 
*  overlaps with the BASEOBJECT::BaseFlags. If the BaseFlags were ever changed,
*  this code may have to be changed to use an InterlockedCompareExchange loop.
*  See BASEOBJECT declaration.
*
*
* Arguments:
*
*   pObj - pointer to object
*
* Return Value:
*
*   None
*
\**************************************************************************/

#define INC_EXCLUSIVE_REF_CNT(pObj) \
    InterlockedIncrement((LONG *)& (((PDD_OBJ) pObj)->cExclusiveLock))
#define DEC_EXCLUSIVE_REF_CNT(pObj) \
    InterlockedDecrement((LONG *)& (((PDD_OBJ) pObj)->cExclusiveLock))


/*******************************Function***********************************\
* VerifyObjectOwner
*
*   Verifies ownership of the object passed in via the PDD_ENTRY.
*
* History:
*
*    21-Feb-1996 -by- Mark Enstrom [marke]
*    12-Mar-2001 -by- Scott Mackowski [ScottMa]  (taken from DDHANDLELOCK)
*
\**************************************************************************/

inline
BOOL VerifyObjectOwner(PDD_ENTRY pentry)
{
    DD_OBJECTOWNER Obj;

    Obj = pentry->ObjectOwner;

    if ((DD_OBJECTOWNER_PID(Obj) != DD_W32GetCurrentPID()) &&
        (DD_OBJECTOWNER_PID(Obj) != OBJECT_OWNER_PUBLIC) )
    {
        return FALSE;
    }

    return TRUE;
}


// Notes on entry structure
//
// The internal entry in the handle manager appears as follows
//
// +-------------------+
// | einfo.pobj, hfree |   4 bytes
// +-------------------+
// | ObjectOwner       |   4 bytes
// +-------------------+
// | FullUnique        |   2 bytes
// +-------------------+
// | Objt              |   1 byte
// +-------------------+
// | Flags             |   1 byte
// +-------------------+
// | dwReserved        |   4 bytes
// +-------------------+
//                 16 bytes total space

#define HMGR_ALLOC_LOCK         0x0001
#define HMGR_ALLOC_ALT_LOCK     0x0002
#define HMGR_NO_ZERO_INIT       0x0004
#define HMGR_MAKE_PUBLIC        0x0008

class DD_ENTRYOBJ : public _DD_ENTRY
{
public:
    DD_ENTRYOBJ()                     { }
   ~DD_ENTRYOBJ()                     { }

    VOID vSetup(PDD_OBJ pObj, DD_OBJTYPE objt_, FSHORT fs)
    {
       DD_OBJECTOWNER ObjNew;
    
       ObjNew = ObjectOwner;
       einfo.pobj = (PDD_OBJ) pObj;
       Objt = objt_;
       Flags = 0;
       dwReserved = NULL;

       if (fs & HMGR_MAKE_PUBLIC)
       {
           DD_SET_OBJECTOWNER_PID(ObjNew,OBJECT_OWNER_PUBLIC);
       }
       else
       {
           DD_SET_OBJECTOWNER_PID(ObjNew,DD_W32GetCurrentPID());
       }

       if (fs & HMGR_ALLOC_LOCK)
       {
           pObj->Tid = (ULONG_PTR)PsGetCurrentThread();
       }

       pObj->cExclusiveLock = (USHORT)(fs & HMGR_ALLOC_LOCK);
       pObj->ulShareCount   = (USHORT)0;

       //
       // Update the ObjectOwner.
       //

       ObjectOwner = ObjNew;    
       
    }

    VOID vFree(UINT uiIndex)
    {
        //
        // handle must already be locked
        //

        DD_ENTRY      *pentry = &gpentDdHmgr[uiIndex];
        DD_OBJECTOWNER ObjNew = pentry->ObjectOwner;

        //
        // Insert the specified handle in the free list.
        //

        pentry->einfo.hFree = ghFreeDdHmgr;

        ghFreeDdHmgr = (HDD_OBJ) (ULONG_PTR)uiIndex;

        //
        // Set the object type to the default type so all handle translations
        // will fail and increment the uniqueness value.
        //

        Objt = (DD_OBJTYPE) DD_DEF_TYPE;
        FullUnique += DD_UNIQUE_INCREMENT;

        //
        // clear user date pointer
        //

        dwReserved = NULL;

        //
        // Clear shared count, set initial pid. Caller
        // must unlock handle.
        //

        DD_SET_OBJECTOWNER_PID(ObjNew,0);
        pentry->ObjectOwner = ObjNew;
    }

    BOOL  bOwnedBy(W32PID pid_)
    {
        return((Objt != DD_DEF_TYPE) && (DD_OBJECTOWNER_PID(ObjectOwner) == (pid_ & DD_PID_BITS)));
    }
};

typedef DD_ENTRYOBJ *PDD_ENTRYOBJ;