/*
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS kernel
 * PURPOSE:          Native driver for dxg implementation
 * FILE:             win32ss/reactx/dxg/eng.c
 * PROGRAMER:        Magnus olsen (magnus@greatlord.com)
 *                   Sebastian Gasiorek (sebastian.gasiorek@reactos.org)
 * REVISION HISTORY:
 *       30/12-2007   Magnus Olsen
 */

#include <dxg_int.h>

/*++
* @name intDdGetDriverInfo
* @implemented
*
* The function intDdGetDriverInfo is used internally in dxg.sys
* It retrieves driver information structures
*
* @param PEDD_DIRECTDRAW_GLOBAL peDdGl
* DirectDraw global structure
*
* @param GUID guid
* GUID of InfoData to read
*
* @param PVOID callbackStruct
* Callback structure pointer
*
* @param ULONG callbackSize
* Size of allocated callback structure
*
* @param ULONG *returnSize
* Desired structure size returned by driver
*
* @return
* Returns true on successful execution, false when error. 
*
* @remarks.
* Only used internally in dxg.sys
*--*/
BOOL intDdGetDriverInfo(PEDD_DIRECTDRAW_GLOBAL peDdGl, GUID guid, PVOID callbackStruct, ULONG callbackSize, ULONG *returnSize)
{
    DD_GETDRIVERINFODATA ddGetDriverInfoData;

    if (peDdGl->ddHalInfo.dwFlags & DDHALINFO_GETDRIVERINFOSET && peDdGl->ddHalInfo.GetDriverInfo)
    {
        memset(&ddGetDriverInfoData, 0, sizeof(DD_GETDRIVERINFODATA));
        ddGetDriverInfoData.dwSize = sizeof(DD_GETDRIVERINFODATA);
        ddGetDriverInfoData.dhpdev = peDdGl->dhpdev;
        memcpy(&ddGetDriverInfoData.guidInfo, &guid, sizeof(GUID));
        ddGetDriverInfoData.dwExpectedSize = callbackSize;
        ddGetDriverInfoData.lpvData = callbackStruct;
        ddGetDriverInfoData.ddRVal = DDERR_CURRENTLYNOTAVAIL;
        if (peDdGl->ddHalInfo.GetDriverInfo(&ddGetDriverInfoData) && !ddGetDriverInfoData.ddRVal)
        {
            if (returnSize)
                *returnSize = ddGetDriverInfoData.dwActualSize;
            return TRUE;
        }

    }

    /* cleanup on error */
    memset(callbackStruct, 0, callbackSize); 
    if (returnSize)
        *returnSize = 0;
    return FALSE;
}

/*++
* @name intDdGetAllDriverInfo
* @implemented
*
* The function intDdGetAllDriverInfo is used internally in dxg.sys
* It retrieves all possible driver information structures
*
* @param PEDD_DIRECTDRAW_GLOBAL peDdGl
* Pointer to destination DirectDrawGlobal structure 
*
* @remarks.
* Only used internally in dxg.sys
* Missing some callbacks (VideoPort, DxApi, AGP)
*--*/
VOID intDdGetAllDriverInfo(PEDD_DIRECTDRAW_GLOBAL peDdGl)
{
    if (peDdGl->ddHalInfo.GetDriverInfo && peDdGl->ddHalInfo.dwFlags & DDHALINFO_GETDRIVERINFOSET)
    {
        intDdGetDriverInfo(peDdGl, GUID_KernelCaps, &peDdGl->ddKernelCaps, sizeof(peDdGl->ddKernelCaps), 0);
        intDdGetDriverInfo(peDdGl, GUID_KernelCallbacks, &peDdGl->ddKernelCallbacks, sizeof(peDdGl->ddKernelCallbacks), 0);

        if (intDdGetDriverInfo(peDdGl, GUID_D3DCallbacks3, &peDdGl->d3dNtHalCallbacks3, sizeof(peDdGl->d3dNtHalCallbacks3), 0))
            peDdGl->dwCallbackFlags |= EDDDGBL_D3DCALLBACKS3;

        if (intDdGetDriverInfo(peDdGl, GUID_ColorControlCallbacks, &peDdGl->ddColorControlCallbacks, sizeof(peDdGl->ddColorControlCallbacks), 0))
            peDdGl->dwCallbackFlags |= EDDDGBL_COLORCONTROLCALLBACKS;

        if (intDdGetDriverInfo(peDdGl, GUID_MiscellaneousCallbacks, &peDdGl->ddMiscellanousCallbacks, sizeof(peDdGl->ddMiscellanousCallbacks), 0))
            peDdGl->dwCallbackFlags |= EDDDGBL_MISCCALLBACKS;

        if (intDdGetDriverInfo(peDdGl, GUID_Miscellaneous2Callbacks, &peDdGl->ddMiscellanous2Callbacks, sizeof(peDdGl->ddMiscellanous2Callbacks), 0))
            peDdGl->dwCallbackFlags |= EDDDGBL_MISC2CALLBACKS;

        if (intDdGetDriverInfo(peDdGl, GUID_NTCallbacks, &peDdGl->ddNtCallbacks, sizeof(peDdGl->ddNtCallbacks), 0) )
            peDdGl->dwCallbackFlags |= EDDDGBL_NTCALLBACKS;

        if (intDdGetDriverInfo(peDdGl, GUID_DDMoreCaps, &peDdGl->ddMoreCaps, sizeof(peDdGl->ddMoreCaps), 0) )
            peDdGl->dwCallbackFlags |= EDDDGBL_DDMORECAPS;

        if (intDdGetDriverInfo(peDdGl, GUID_NTPrivateDriverCaps, &peDdGl->ddNtPrivateDriverCaps, sizeof(peDdGl->ddNtPrivateDriverCaps), 0) )
            peDdGl->dwCallbackFlags |= EDDDGBL_PRIVATEDRIVERCAPS;

        if (intDdGetDriverInfo(peDdGl, GUID_MotionCompCallbacks, &peDdGl->ddMotionCompCallbacks, sizeof(peDdGl->ddMotionCompCallbacks), 0) )
            peDdGl->dwCallbackFlags |= EDDDGBL_MOTIONCOMPCALLBACKS;
    }
}

/*++
* @name intDdEnableDriver
* @implemented
*
* The function intDdEnableDriver is used internally in dxg.sys
* Fills in all EDD_DIRECTDRAW_GLOBAL structures and enables DirectDraw acceleration when possible
*
* @param PEDD_DIRECTDRAW_GLOBAL peDdGl
* Pointer to destination DirectDrawGlobal structure 
*
* @remarks.
* Only used internally in dxg.sys
*--*/
VOID intDdEnableDriver(PEDD_DIRECTDRAW_GLOBAL peDdGl)
{
    PDRIVER_FUNCTIONS  DriverFunctions;
    LPD3DNTHAL_GLOBALDRIVERDATA GlobalDriverData;
    LPD3DNTHAL_CALLBACKS HalCallbacks;
    PDD_D3DBUFCALLBACKS D3DBufCallbacks;


    gpEngFuncs.DxEngLockHdev(peDdGl->hDev);
    DriverFunctions = (PDRIVER_FUNCTIONS)gpEngFuncs.DxEngGetHdevData(peDdGl->hDev, DxEGShDevData_DrvFuncs);

    // check if driver has DirectDraw functions
    if ((!DriverFunctions->GetDirectDrawInfo)||(!DriverFunctions->EnableDirectDraw)||(!DriverFunctions->DisableDirectDraw))
        peDdGl->dhpdev = 0;


    // reset acceleration flag
    peDdGl->fl = peDdGl->fl & 0xFFFFFFFE;

    // ask for structure sizes
    if ((peDdGl->dhpdev)&&(DriverFunctions->GetDirectDrawInfo(peDdGl->dhpdev, &peDdGl->ddHalInfo, &peDdGl->dwNumHeaps, NULL, &peDdGl->dwNumFourCC, NULL)))
    {
        // allocate memory for DX data
        if (peDdGl->dwNumHeaps)
            peDdGl->pvmList = EngAllocMem(FL_ZERO_MEMORY, peDdGl->dwNumHeaps*sizeof(VIDEOMEMORY), TAG_GDDV);
        if (peDdGl->dwNumFourCC)
            peDdGl->pdwFourCC = EngAllocMem(FL_ZERO_MEMORY, peDdGl->dwNumFourCC * 4, TAG_GDDF);

        // get data from driver
        if (!DriverFunctions->GetDirectDrawInfo(peDdGl->dhpdev, &peDdGl->ddHalInfo, &peDdGl->dwNumHeaps, peDdGl->pvmList, &peDdGl->dwNumFourCC, peDdGl->pdwFourCC))
        {
            // failed - cleanup and exit
            if (peDdGl->pvmList)
                EngFreeMem(peDdGl->pvmList);
            if (peDdGl->pdwFourCC)
                EngFreeMem(peDdGl->pdwFourCC);
            gpEngFuncs.DxEngUnlockHdev(peDdGl->hDev);
            return;
        }

        // check if we can enable DirectDraw acceleration
        if ((peDdGl->ddHalInfo.vmiData.pvPrimary) &&
            (DriverFunctions->EnableDirectDraw(peDdGl->dhpdev, &peDdGl->ddCallbacks, &peDdGl->ddSurfaceCallbacks, &peDdGl->ddPaletteCallbacks))&&
            !(gpEngFuncs.DxEngGetHdevData(peDdGl->hDev, DxEGShDevData_dd_flags) & CapOver_DisableD3DAccel)&&
            (peDdGl->ddHalInfo.dwSize == sizeof(DD_HALINFO)))
        {
            GlobalDriverData = peDdGl->ddHalInfo.lpD3DGlobalDriverData;
            HalCallbacks = peDdGl->ddHalInfo.lpD3DHALCallbacks;
            D3DBufCallbacks = peDdGl->ddHalInfo.lpD3DHALCallbacks;

            if (GlobalDriverData && GlobalDriverData->dwSize == sizeof(D3DNTHAL_GLOBALDRIVERDATA))
                memcpy(&peDdGl->d3dNtGlobalDriverData, GlobalDriverData, sizeof(D3DNTHAL_GLOBALDRIVERDATA));

            if (HalCallbacks && HalCallbacks->dwSize == sizeof(D3DNTHAL_CALLBACKS))
                memcpy(&peDdGl->d3dNtHalCallbacks, HalCallbacks, sizeof(D3DNTHAL_CALLBACKS));

            if (D3DBufCallbacks && D3DBufCallbacks->dwSize == sizeof(DD_D3DBUFCALLBACKS))
                memcpy(&peDdGl->d3dBufCallbacks, D3DBufCallbacks, sizeof(DD_D3DBUFCALLBACKS));

            intDdGetAllDriverInfo(peDdGl);

            // enable DirectDraw acceleration
            peDdGl->fl |= 1;
        }
        else
        {
            // failed - cleanup and exit
            if (peDdGl->pvmList)
                EngFreeMem(peDdGl->pvmList);
            if (peDdGl->pdwFourCC)
                EngFreeMem(peDdGl->pdwFourCC);
        }
    }

    gpEngFuncs.DxEngUnlockHdev(peDdGl->hDev);
}

PVOID
FASTCALL
intDdCreateDirectDrawLocal(HDEV hDev)
{
    PEDD_DIRECTDRAW_GLOBAL peDdGl = NULL;
    PEDD_DIRECTDRAW_LOCAL peDdL = NULL;
    PDD_ENTRY AllocRet;

    peDdGl = (PEDD_DIRECTDRAW_GLOBAL)gpEngFuncs.DxEngGetHdevData(hDev, DxEGShDevData_eddg);

    AllocRet = DdHmgAlloc(sizeof(EDD_DIRECTDRAW_LOCAL), ObjType_DDLOCAL_TYPE, TRUE);
    if (!AllocRet) 
        return NULL;

    peDdL = (PEDD_DIRECTDRAW_LOCAL)AllocRet->pobj;

    /* initialize DIRECTDRAW_LOCAL */
    peDdL->peDirectDrawLocal_prev = peDdGl->peDirectDrawLocalList;
    peDdL->hCreatorProcess = PsGetCurrentThreadProcessId();
    peDdL->Process = PsGetCurrentProcess();

    // link DirectDrawGlobal and DirectDrawLocal
    peDdGl->peDirectDrawLocalList = peDdL;
    peDdL->peDirectDrawGlobal = peDdGl;
    peDdL->peDirectDrawGlobal2 = peDdGl;

    gpEngFuncs.DxEngReferenceHdev(hDev);

    InterlockedDecrement((VOID*)&peDdL->pobj.cExclusiveLock);

    return peDdL->pobj.hHmgr;
}

/*++
* @name DxDdCreateDirectDrawObject
* @implemented
*
* Function creates new DirectDraw object
*
* @param HDC hDC
* Device context handle 
*
* @return
* Newly created DirectDraw object handle. 
*
* @remarks.
* Missing all AGP stuff
*--*/
DWORD
NTAPI
DxDdCreateDirectDrawObject(
    HDC hDC)
{
    PDC pDC = NULL;
    HDEV hDev = NULL;
    DWORD_PTR retVal = 0;

    pDC = gpEngFuncs.DxEngLockDC(hDC);
    if (!pDC)
        return 0;

    // get driver hDev from DC
    hDev = (HDEV)gpEngFuncs.DxEngGetDCState(hDC, 3);
    if (!hDev) {
        gpEngFuncs.DxEngUnlockDC(pDC);
        return 0;
    }

    // is this primary display?
    if (!gpEngFuncs.DxEngGetHdevData(hDev, DxEGShDevData_display))
    {
        gpEngFuncs.DxEngUnlockDC(pDC);
        return 0;
    }

    gpEngFuncs.DxEngLockHdev(hDev);

    // create object only for 8BPP and more
    if (gpEngFuncs.DxEngGetHdevData(hDev, DxEGShDevData_DitherFmt) >= BMF_8BPP)
        retVal = (DWORD_PTR)intDdCreateDirectDrawLocal(hDev);

    gpEngFuncs.DxEngUnlockHdev(hDev);
    gpEngFuncs.DxEngUnlockDC(pDC);
    return retVal;
}


/*++
* @name DxDdGetDriverInfo
* @implemented
*
* Function queries the driver for DirectDraw and Direct3D functionality
*
* @param HANDLE DdHandle
* Handle to DirectDraw object 
*
* @param PDD_GETDRIVERINFODATA drvInfoData
* Pointer to in/out driver info data structure 
*--*/
DWORD
NTAPI
DxDdGetDriverInfo(HANDLE DdHandle, PDD_GETDRIVERINFODATA drvInfoData)
{
    PEDD_DIRECTDRAW_LOCAL peDdL;
    PEDD_DIRECTDRAW_GLOBAL peDdGl;
    PVOID pInfo = NULL;
    DWORD dwInfoSize = 0;
    BYTE callbackStruct[1024];
    DWORD RetVal = FALSE;

    peDdL = (PEDD_DIRECTDRAW_LOCAL)DdHmgLock(DdHandle, ObjType_DDLOCAL_TYPE, FALSE);
    if (!peDdL)
        return RetVal;
    
    peDdGl = peDdL->peDirectDrawGlobal2;

    // check VideoPort related callbacks
    if (peDdGl->dwCallbackFlags & EDDDGBL_VIDEOPORTCALLBACKS)
    {
        if (InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_VideoPortCallbacks))
        {
            dwInfoSize = sizeof(DD_VIDEOPORTCALLBACKS);
            pInfo = (VOID*)&peDdGl->ddVideoPortCallback;
        }
        if (InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_VideoPortCaps))
        {
            pInfo = (VOID*)peDdGl->lpDDVideoPortCaps;
            dwInfoSize = 72 * peDdGl->ddHalInfo.ddCaps.dwMaxVideoPorts;
        }
        if (InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_D3DCallbacks3))
        {
            dwInfoSize = sizeof(D3DNTHAL_CALLBACKS3);
            pInfo = (VOID*)&peDdGl->d3dNtHalCallbacks3;
        }
    }

    // check ColorControl related callbacks
    if (peDdGl->dwCallbackFlags & EDDDGBL_COLORCONTROLCALLBACKS)
    {
        if (InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_ColorControlCallbacks))
        {
            dwInfoSize = sizeof(DD_COLORCONTROLCALLBACKS);
            pInfo = (VOID*)&peDdGl->ddColorControlCallbacks;
        }
        if (InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_NTCallbacks))
        {
            dwInfoSize = sizeof(DD_NTCALLBACKS);
            pInfo = (VOID*)&peDdGl->ddNtCallbacks;
        }      
    }

    // check Miscellaneous callbacks
    if (peDdGl->dwCallbackFlags & EDDDGBL_MISCCALLBACKS)
    {
        if (InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_MiscellaneousCallbacks))
        {
            dwInfoSize = sizeof(DD_MISCELLANEOUSCALLBACKS);
            pInfo = (VOID*)&peDdGl->ddMiscellanousCallbacks;
        }
        if (InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_DDMoreCaps))
        {
            dwInfoSize = sizeof(DD_MORECAPS);
            pInfo = &peDdGl->ddMoreCaps;
        }
    }

    if (peDdGl->dwCallbackFlags & EDDDGBL_MISC2CALLBACKS && 
        InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_Miscellaneous2Callbacks))
    {
        dwInfoSize = sizeof(DD_MISCELLANEOUS2CALLBACKS);
        pInfo = (VOID*)&peDdGl->ddMiscellanous2Callbacks;
    }

    if (peDdGl->dwCallbackFlags & EDDDGBL_MOTIONCOMPCALLBACKS && 
        InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_MotionCompCallbacks))
    {
        dwInfoSize = sizeof(DD_MOTIONCOMPCALLBACKS);
        pInfo = (VOID*)&peDdGl->ddMotionCompCallbacks;
    }

    if (InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_KernelCaps) )
    {
        dwInfoSize = sizeof(DD_KERNELCALLBACKS);
        pInfo = &peDdGl->ddKernelCaps;
    }

    if (InlineIsEqualGUID(&drvInfoData->guidInfo, &GUID_DDMoreSurfaceCaps))
    {
        dwInfoSize = sizeof(DDMORESURFACECAPS);
        pInfo = &peDdGl->ddMoreSurfaceCaps;
    }

    if (dwInfoSize && pInfo)
    {
        gpEngFuncs.DxEngLockHdev(peDdGl->hDev);
        intDdGetDriverInfo(peDdGl, drvInfoData->guidInfo, &callbackStruct, dwInfoSize, &dwInfoSize);
        gpEngFuncs.DxEngUnlockHdev(peDdGl->hDev);
        memcpy(drvInfoData->lpvData, callbackStruct, dwInfoSize);
    }

    InterlockedDecrement((VOID*)&peDdL->pobj.cExclusiveLock);

    return TRUE;
}

/*++
* @name DxDdQueryDirectDrawObject
* @implemented
*
* Function queries the DirectDraw object for its functionality
*  
* @return
* TRUE on success. 
*--*/
BOOL
NTAPI
DxDdQueryDirectDrawObject(
    HANDLE DdHandle,
    DD_HALINFO* pDdHalInfo,
    DWORD* pCallBackFlags,
    LPD3DNTHAL_CALLBACKS pd3dNtHalCallbacks,
    LPD3DNTHAL_GLOBALDRIVERDATA pd3dNtGlobalDriverData,
    PDD_D3DBUFCALLBACKS pd3dBufCallbacks,
    LPDDSURFACEDESC pTextureFormats,
    DWORD* p8,
    VIDEOMEMORY* p9,
    DWORD* pdwNumFourCC,
    DWORD* pdwFourCC)
{
    PEDD_DIRECTDRAW_LOCAL peDdL;
    PEDD_DIRECTDRAW_GLOBAL peDdGl;
    BOOL RetVal = FALSE;

    if (!DdHandle)
        return RetVal;

    if (!pDdHalInfo)
        return RetVal;

    if (!gpEngFuncs.DxEngScreenAccessCheck())
        return RetVal;

    peDdL = (PEDD_DIRECTDRAW_LOCAL)DdHmgLock(DdHandle, ObjType_DDLOCAL_TYPE, FALSE);
    if (peDdL)
    {
        peDdGl = peDdL->peDirectDrawGlobal2;
        gpEngFuncs.DxEngLockHdev(peDdGl->hDev);

        memcpy(pDdHalInfo, &peDdGl->ddHalInfo, sizeof(DD_HALINFO));

        if (pCallBackFlags)
        {
            *(DWORD*)pCallBackFlags = peDdGl->ddCallbacks.dwFlags;
            *(DWORD*)((ULONG_PTR)pCallBackFlags + 4) = peDdGl->ddSurfaceCallbacks.dwFlags;
            *(DWORD*)((ULONG_PTR)pCallBackFlags + 8) = peDdGl->ddPaletteCallbacks.dwFlags;
        }

        if (pd3dNtHalCallbacks)
            memcpy(pd3dNtHalCallbacks, &peDdGl->d3dNtHalCallbacks, sizeof(peDdGl->d3dNtHalCallbacks));

        if (pd3dNtGlobalDriverData)
            memcpy(pd3dNtGlobalDriverData, &peDdGl->d3dNtGlobalDriverData, sizeof(peDdGl->d3dNtGlobalDriverData));

        if (pd3dBufCallbacks)
            memcpy(pd3dBufCallbacks, &peDdGl->d3dBufCallbacks, sizeof(peDdGl->d3dBufCallbacks));

        if (pTextureFormats)
            memcpy(pTextureFormats, &peDdGl->d3dNtGlobalDriverData.lpTextureFormats, peDdGl->d3dNtGlobalDriverData.dwNumTextureFormats * sizeof(DDSURFACEDESC2));

        if (pdwNumFourCC)
            *pdwNumFourCC = peDdGl->dwNumFourCC;

        if (pdwFourCC)
            memcpy(pdwFourCC, &peDdGl->pdwFourCC, 4 * peDdGl->dwNumFourCC);

        RetVal = TRUE;

        gpEngFuncs.DxEngUnlockHdev(peDdGl->hDev);
  
        InterlockedDecrement((VOID*)&peDdL->pobj.cExclusiveLock);
    }

    return RetVal;
}

/*++
* @name DxDdEnableDirectDraw
* @implemented
*
* Function enables DirectDraw
*
* @param PEDD_DIRECTDRAW_GLOBAL peDdGl
* Pointer to destination DirectDrawGlobal structure 
*--*/
BOOL
NTAPI
DxDdEnableDirectDraw(HANDLE hDev, BOOL arg2/*What for?*/)
{
    PEDD_DIRECTDRAW_GLOBAL peDdGl = NULL;

    if (gpEngFuncs.DxEngGetHdevData(hDev, DxEGShDevData_display))
    {
        peDdGl = (PEDD_DIRECTDRAW_GLOBAL)gpEngFuncs.DxEngGetHdevData(hDev, DxEGShDevData_eddg);
        peDdGl->hDev = hDev;
        peDdGl->bSuspended = FALSE;
        peDdGl->dhpdev = (PVOID)gpEngFuncs.DxEngGetHdevData(hDev, DxEGShDevData_dhpdev);
        intDdEnableDriver(peDdGl);
        return TRUE;
    }

    return FALSE;
}

/*++
* @name DxDdReenableDirectDrawObject
* @implemented
*
* Function re-enables DirectDraw object after mode switch
*  
* @param HANDLE DdHandle
* DirectDraw object handle 
*
* @param PVOID p2
* ??? 
*
* @return
* TRUE on success. 
*
* @remarks
* Missing all AGP stuff and second parameter handling
*--*/
DWORD
NTAPI
DxDdReenableDirectDrawObject(
    HANDLE DdHandle,
    PVOID p2)
{
    PEDD_DIRECTDRAW_LOCAL peDdL;
    PEDD_DIRECTDRAW_GLOBAL peDdGl;
    HDC hDC;                     
    DWORD RetVal = FALSE;

    peDdL = (PEDD_DIRECTDRAW_LOCAL)DdHmgLock(DdHandle, ObjType_DDLOCAL_TYPE, FALSE);

    if (!peDdL)
        return RetVal;

    peDdGl = peDdL->peDirectDrawGlobal2;

    hDC = gpEngFuncs.DxEngGetDesktopDC(0, FALSE, FALSE);

    gpEngFuncs.DxEngLockShareSem();
    gpEngFuncs.DxEngLockHdev(peDdGl->hDev);

    if (peDdGl->fl & 1 &&
        gpEngFuncs.DxEngGetDCState(hDC, 2) != 1 &&
        !(gpEngFuncs.DxEngGetHdevData(peDdGl->hDev, DxEGShDevData_OpenRefs)) &&
        !(gpEngFuncs.DxEngGetHdevData(peDdGl->hDev, DxEGShDevData_disable)) &&
        !(gpEngFuncs.DxEngGetHdevData(peDdGl->hDev, DxEGShDevData_dd_nCount)) &&
        gpEngFuncs.DxEngGetHdevData(peDdGl->hDev, DxEGShDevData_DitherFmt) >= BMF_8BPP)
    {
        // reset acceleration and suspend flags
        peDdGl->fl &= 0xFFFFFFFD;
        peDdGl->bSuspended = 0;
        peDdGl->dhpdev = (PVOID)gpEngFuncs.DxEngGetHdevData(peDdGl->hDev, DxEGShDevData_dhpdev);

        RetVal = TRUE;
        // FIXME AGP Stuff
    }

    gpEngFuncs.DxEngUnlockHdev(peDdGl->hDev);
    gpEngFuncs.DxEngUnlockShareSem();

    InterlockedDecrement((VOID*)&peDdL->pobj.cExclusiveLock);

    return RetVal;
}

PEDD_SURFACE
NTAPI
intDdCreateNewSurfaceObject(PEDD_DIRECTDRAW_LOCAL peDdL, HANDLE hDirectDrawLocal, PDD_SURFACE_GLOBAL pDdSurfGlob, PDD_SURFACE_LOCAL pDdSurfLoc, PDD_SURFACE_MORE pDdSurfMore)
{
    PEDD_SURFACE pSurface = NULL;

    // first check if we can assign it from current ddHandle
    if (hDirectDrawLocal)
    {
        pSurface = (PEDD_SURFACE)DdHmgLock(hDirectDrawLocal, ObjType_DDSURFACE_TYPE, FALSE);
        // check if surface is locked and belongs to correct DirectDrawLocal
        if ((pSurface)&&((pSurface->peDirectDrawLocal != peDdL)||(!pSurface->hSecure)))
        {
            InterlockedDecrement((VOID*)&peDdL->pobj.cExclusiveLock);
            return NULL;
        }
    }

    // if surface not found from ddHandle or ddHandle not provided
    if (!pSurface)
    {
        // create new surface object
        pSurface = (PEDD_SURFACE)DdHmgAlloc(sizeof(EDD_SURFACE), ObjType_DDSURFACE_TYPE, TRUE);
        if (pSurface)
        {
            pSurface->ddsSurfaceLocal.lpGbl = &pSurface->ddsSurfaceGlobal;
            pSurface->ddsSurfaceLocal.lpSurfMore = &pSurface->ddsSurfaceMore;
            pSurface->ddsSurfaceInt.lpLcl = &pSurface->ddsSurfaceLocal;
            pSurface->peDirectDrawLocal = peDdL;
            pSurface->peDirectDrawGlobalNext = peDdL->peDirectDrawGlobal2;
            pSurface->ldev = gpEngFuncs.DxEngGetHdevData(pSurface->peDirectDrawGlobalNext->hDev, DxEGShDevData_ldev);
            pSurface->gdev = gpEngFuncs.DxEngGetHdevData(pSurface->peDirectDrawGlobalNext->hDev, DxEGShDevData_GDev);
            pSurface->hSecure = (VOID*)1;
        }
    }

    if (pSurface)
    {
        pSurface->ddsSurfaceGlobal.fpVidMem = pDdSurfGlob->fpVidMem;
        pSurface->ddsSurfaceGlobal.lPitch = pDdSurfGlob->lPitch;
        pSurface->ddsSurfaceGlobal.wWidth = pDdSurfGlob->wWidth;
        pSurface->ddsSurfaceGlobal.wHeight = pDdSurfGlob->wHeight;
        pSurface->wWidth = pDdSurfGlob->wWidth;
        pSurface->wHeight = pDdSurfGlob->wHeight;
        memcpy(&pSurface->ddsSurfaceGlobal.ddpfSurface, &pDdSurfGlob->ddpfSurface, sizeof(pSurface->ddsSurfaceGlobal.ddpfSurface));
        pSurface->ddsSurfaceLocal.ddsCaps.dwCaps = pDdSurfLoc->ddsCaps.dwCaps;
        pSurface->ddsSurfaceMore.ddsCapsEx.dwCaps2 = pDdSurfMore->ddsCapsEx.dwCaps2;
        pSurface->ddsSurfaceMore.ddsCapsEx.dwCaps3 = pDdSurfMore->ddsCapsEx.dwCaps3;
        pSurface->ddsSurfaceMore.ddsCapsEx.dwCaps4 = pDdSurfMore->ddsCapsEx.dwCaps4;
        pSurface->ddsSurfaceMore.dwSurfaceHandle = pDdSurfMore->dwSurfaceHandle;
        pSurface->hSecure = (VOID*)1;

        peDdL->peSurface_DdList = pSurface;
        peDdL->hSurface = (ULONG_PTR)pSurface->pobj.hHmgr;
    }

    return pSurface;
}

HANDLE
NTAPI
DxDdCreateSurfaceObject(HANDLE hDirectDrawLocal,
                        HANDLE hSurface,
                        PDD_SURFACE_LOCAL puSurfaceLocal,
                        PDD_SURFACE_MORE puSurfaceMore,
                        PDD_SURFACE_GLOBAL puSurfaceGlobal,
                        BOOL bComplete)
{
    HANDLE RetVal = FALSE;
    PEDD_DIRECTDRAW_LOCAL peDdL = NULL;
    PEDD_SURFACE pDdSurface = NULL;

    peDdL = (PEDD_DIRECTDRAW_LOCAL)DdHmgLock(hDirectDrawLocal, ObjType_DDLOCAL_TYPE, FALSE);

    if (!peDdL)
        return RetVal;

    pDdSurface = intDdCreateNewSurfaceObject(peDdL, hSurface, puSurfaceGlobal, puSurfaceLocal, puSurfaceMore);
    if (!pDdSurface)
    {
        InterlockedDecrement((VOID*)&peDdL->pobj.cExclusiveLock);
        return RetVal;
    }

    RetVal = pDdSurface->pobj.hHmgr;

    InterlockedDecrement((VOID*)&pDdSurface->pobj.cExclusiveLock);
    InterlockedDecrement((VOID*)&peDdL->pobj.cExclusiveLock);

    return RetVal;
}