text: /******************************Module*Header**********************************\
  *
  *                           **************************
  *                           * DirectDraw SAMPLE CODE *
  *                           **************************
  *
  * Module Name: ddenable.c
  *
  * Content: Windows 2000 only DirectDraw/D3D enabling functions
  *
  * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
  * Copyright (c) 1995-2003 Microsoft Corporation.  All rights reserved.
  \*****************************************************************************/
  #include "glint.h"
  
  #if WNT_DDRAW
  
  //-----------------------------------------------------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // __DDE_BuildPixelFormat
  //
  // generate a pixel format structure based on the mode
  // This example works only with RGB surfaces
  //
  //-----------------------------------------------------------------------------
  void 
  __DDE_BuildPixelFormat(
      P3_THUNKEDDATA* pThisDisplay,
      LPGLINTINFO pGLInfo,
      LPDDPIXELFORMAT pdpf )
  {
      PPDEV ppdev;
  
      ppdev = pThisDisplay->ppdev;
  
      pdpf->dwSize = sizeof( DDPIXELFORMAT );
      pdpf->dwFourCC = 0;
  
      pdpf->dwFlags = DDPF_RGB;
  
      if( pGLInfo->dwBpp == 8 )
      {
          pdpf->dwFlags |= DDPF_PALETTEINDEXED8;
      }
      pdpf->dwRGBBitCount = pGLInfo->dwBpp;
  
      pdpf->dwRBitMask = ppdev->flRed;
      pdpf->dwGBitMask = ppdev->flGreen;
      pdpf->dwBBitMask = ppdev->flBlue;
  
      // Calculate the alpha channel as it isn't in the ppdev
      switch (pGLInfo->dwBpp)
      {
          case 8:
              DISPDBG((DBGLVL, "Format is 8 bits"));
              pdpf->dwRGBAlphaBitMask = 0;
              break;
              
          case 16:
              DISPDBG((DBGLVL, "Format is 16 bits"));
              switch(ppdev->flRed)
              {
                  case 0x7C00:
                      pdpf->dwRGBAlphaBitMask = 0x8000L;
                      pdpf->dwFlags |= DDPF_ALPHAPIXELS;
                      break;
                  default:
                      pdpf->dwRGBAlphaBitMask = 0x0L;
              }
              break;
          case 24:
              DISPDBG((DBGLVL, "Format is 24 bits"));
              pdpf->dwRGBAlphaBitMask = 0x00000000L;
              break;
          case 32:
              DISPDBG((DBGLVL, "Desktop is 32 bits"));
              pdpf->dwRGBAlphaBitMask = 0xff000000L;
              pdpf->dwFlags |= DDPF_ALPHAPIXELS;
              break;
              
      }
  } // __DDE_BuildPixelFormat 
  
  //-----------------------------------------------------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // __DDE_bSetupDDStructs
  //
  // This fills in the data that would have been setup on Win9X in the
  // 16 bit side
  // 
  //-----------------------------------------------------------------------------
  BOOL 
  __DDE_bSetupDDStructs( 
      P3_THUNKEDDATA* pThisDisplay, 
      BOOL reset )
  {
      DWORD dwRegistryValue;
      BOOL bSuccess;
      LPGLINTINFO pGLInfo;
      PPDEV ppdev;
      void *fbPtr;            // Framebuffer pointer
      void *lbPtr;            // Localbuffer pointer
      DWORD fbSizeInBytes;    // Size of framebuffer
      DWORD lbSizeInBytes;    // Size of localbuffer
      DWORD fbOffsetInBytes;  // Offset to 1st 'free' byte in framebuffer
      DWORD dwMemStart, dwMemEnd;
  
      // reset == TRUE if there has been a mode change.
      pThisDisplay->bResetMode = reset;
  
  #if DBG
      if (pThisDisplay->bResetMode)
      {
          DISPDBG((DBGLVL,"Resetting due to mode change"));
      }
      else
      {
          DISPDBG((DBGLVL, "Creating for the first time"));
      }
  #endif
  
      // Setup pThisDisplay->pGLInfo from PPDEV
      pGLInfo = pThisDisplay->pGLInfo;
      ppdev = pThisDisplay->ppdev;
  
      GetFBLBInfoForDDraw (ppdev, 
                            &fbPtr,               // Framebuffer pointer
                            &lbPtr,               // Localbuffer pointer,
                                                  //     (*** This is NULL***)
                            &fbSizeInBytes,       // Size of framebuffer
                            &lbSizeInBytes,       // Size of localbuffer
                            &fbOffsetInBytes,     // Offset to 1st 'free' byte 
                                                  //     in framebuffer
                            &pGLInfo->bDRAMBoard);// TRUE if SDRAM vidmem, 
                                                  //   FALSE if SGRAM 
                                                  //   (i.e. hw writemask) vidmem
  
  
      DISPDBG((DBGLVL, "__DDE_bSetupDDStructs: fbPtr 0x%lx, fbOff 0x%x", 
                       fbPtr, fbOffsetInBytes));
  
      // If VBlankStatusPtr is non-NULL then we know that the NT miniport 
      // will set the VBlankStatusPtr for us.
      if (pThisDisplay->VBlankStatusPtr)
          pGLInfo->dwFlags = GMVF_VBLANK_ENABLED;// Say that we are using VBLANKs
      else
          pGLInfo->dwFlags = 0;
  
      pGLInfo->bPixelToBytesShift = (unsigned char)ppdev->cPelSize;
      pGLInfo->ddFBSize = fbSizeInBytes;
      pGLInfo->dwScreenBase = 0;
      pGLInfo->dwOffscreenBase = fbOffsetInBytes;
  
      pGLInfo->dwScreenWidth = ppdev->cxScreen;   // Driver info
      pGLInfo->dwScreenHeight = ppdev->cyScreen;
      pGLInfo->dwVideoWidth = ppdev->cxMemory;
      pGLInfo->dwVideoHeight = ppdev->cyMemory;
  
      bSuccess = GET_REGISTRY_ULONG_FROM_STRING(
                          "HardwareInformation.CurrentPixelClockSpeed",
                          &dwRegistryValue);
      if(!bSuccess)
      {
          DISPDBG((ERRLVL,"Error - can't determine pixel clock"));
          dwRegistryValue = 0;
      }
      DISPDBG((DBGLVL,"Pixel clock frequency is %dHz", dwRegistryValue));
      pGLInfo->PixelClockFrequency = dwRegistryValue;
  
      bSuccess = GET_REGISTRY_ULONG_FROM_STRING(
                          "HardwareInformation.CurrentMemClockSpeed", 
                          &dwRegistryValue);
      if(!bSuccess)
      {
          DISPDBG((ERRLVL,"Error - can't determine memory clock"));
          dwRegistryValue = 0;
      }
      
      DISPDBG((DBGLVL,"Memory clock frequency is %dHz", dwRegistryValue));
      pGLInfo->MClkFrequency = dwRegistryValue;
  
      if (ppdev->iBitmapFormat == BMF_8BPP)
      {
          DISPDBG((DBGLVL, "Desktop is 8 bits"));
          pGLInfo->dwBpp = 8;
      }
      else if (ppdev->iBitmapFormat == BMF_16BPP)
      {
          DISPDBG((DBGLVL, "Desktop is 16 bits"));
          pGLInfo->dwBpp = 16;
      }
      else if (ppdev->iBitmapFormat == BMF_24BPP)
      {
          DISPDBG((DBGLVL, "Desktop is 24 bits"));
          pGLInfo->dwBpp = 24;
      }
      else
      {
          DISPDBG((DBGLVL, "Desktop is 32 bits"));
          pGLInfo->dwBpp = 32;
      }
  
      pGLInfo->dwScreenWidthBytes = ppdev->lDelta;
  
      if (pGLInfo->pRegs == 0)
      {
          DISPDBG ((WRNLVL, "__DDE_bSetupDDStructs: NULL register set"));
          return (FALSE);
      }
  
      // Setup the information that is shared with the 32 bit side
      // Control points to the RAMDAC
      // pGLInfo is a pointer to the DisplayDriver state.
      pThisDisplay->pGLInfo = pGLInfo;
      pThisDisplay->control = (FLATPTR) pGLInfo->pRegs;
  
      // NT uses offsets for its memory addresses
      pThisDisplay->dwScreenFlatAddr = 0;
      pThisDisplay->dwLocalBuffer = 0;
  
      __DDE_BuildPixelFormat( pThisDisplay, 
                          (LPGLINTINFO) pThisDisplay->pGLInfo, 
                          &pThisDisplay->ddpfDisplay );
  
      // Setup the display size information
      // dwScreenWidth, dwScreenHeight = current resolution
      // cxMemory = Pixels across for one scanline 
      //              (not necessarily the same as the screen width)
      // cyMemory = Scanline height of the memory
      // dwScreenStart = First visible line of display
      pThisDisplay->dwScreenWidth = pGLInfo->dwScreenWidth;
      pThisDisplay->dwScreenHeight = pGLInfo->dwScreenHeight;
      pThisDisplay->cxMemory = pGLInfo->dwScreenWidth;
  
      pThisDisplay->dwScreenStart = pThisDisplay->dwScreenFlatAddr + 
                                                          pGLInfo->dwScreenBase;
      
      // Usefull constants used during blits.
      if (pThisDisplay->ddpfDisplay.dwRGBBitCount == 24)
      {
          // The driver will detect these strange values and handle appropriately
          pThisDisplay->bPixShift = 4;
          pThisDisplay->bBppShift = 4;
          pThisDisplay->dwBppMask = 4;
          
          pThisDisplay->cyMemory = pGLInfo->ddFBSize / 
                                      (pThisDisplay->dwScreenWidth * 3);
      }
      else
      {
          // = 2,1,0 for 32,16,8 depth.  Shifts needed to calculate bytes/pixel
          pThisDisplay->bPixShift = 
                              (BYTE)pThisDisplay->ddpfDisplay.dwRGBBitCount >> 4;
          // = 0,1,2 for 32/16/8.
          pThisDisplay->bBppShift = 2 - pThisDisplay->bPixShift;
          // = 3,1,0 for 8,16,32 bpp
          pThisDisplay->dwBppMask = 3 >> pThisDisplay->bPixShift;
  
          pThisDisplay->cyMemory = 
                          pGLInfo->ddFBSize / 
                              (pThisDisplay->dwScreenWidth <<  
                                  (pThisDisplay->ddpfDisplay.dwRGBBitCount >> 4));
      }
  
      // On Windows NT, we manage a region of memory starting from 0 
      //(all pointers are offsets from the start of the mapped memory)
      dwMemStart = pGLInfo->dwOffscreenBase;
      dwMemEnd = pGLInfo->ddFBSize - 1;
  
      // Round up the start pointer and round down the end pointer
      dwMemStart = (dwMemStart + 3) & ~3;
      dwMemEnd = dwMemEnd & ~3;
      
      // Now make the end pointer inclusive
      dwMemEnd -= 1;
  
      DISPDBG((DBGLVL,"Heap Attributes:"));
      DISPDBG((DBGLVL,"  Start of Heap Memory: 0x%lx", 
                  pThisDisplay->LocalVideoHeap0Info.dwMemStart));
      DISPDBG((DBGLVL,"  End of Heap Memory: 0x%lx", 
                  pThisDisplay->LocalVideoHeap0Info.dwMemEnd));
  
      // If we already have a heap setup and the mode has changed
      // we free the Heap manager
      if (pThisDisplay->bDDHeapManager)
      {
          if (pThisDisplay->bResetMode)
          {
              // The mode has been changed.  
              // We need to free the allocator and re-create it
              _DX_LIN_UnInitialiseHeapManager(&pThisDisplay->LocalVideoHeap0Info);
  
              // Start the allocator off again.
              _DX_LIN_InitialiseHeapManager(&pThisDisplay->LocalVideoHeap0Info,
                                            dwMemStart,
                                            dwMemEnd);
          }
      }
      else
      {
          // This must be the first instance of a created driver,
          // so create the Heap and remember that it is created.
          _DX_LIN_InitialiseHeapManager(&pThisDisplay->LocalVideoHeap0Info,
                                        dwMemStart,
                                        dwMemEnd);
          pThisDisplay->bDDHeapManager = TRUE;
      }
  
      if(ppdev->flStatus & ENABLE_LINEAR_HEAP)
      {
          // save away the heap info we really need, we won't actually 
          // enable the DX managed heap until we get a 
          // DrvNotify(DN_DRAWING_BEGIN)
          ppdev->heap.pvmLinearHeap = &pThisDisplay->LocalVideoHeap0Info;
          ppdev->heap.cLinearHeaps = 1;
      }
  
      return TRUE;
  } // __DDE_bSetupDDStructs
  
  //-----------------------------------------------------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // __DDE_bDestroyDDStructs
  //
  // Disable the linear allocator.  
  //
  //-----------------------------------------------------------------------------
  BOOL 
  __DDE_bDestroyDDStructs ( 
      P3_THUNKEDDATA* pThisDisplay )
  {
      // Release the linear allocator
      if (pThisDisplay->bDDHeapManager)
      {
          _DX_LIN_UnInitialiseHeapManager(&pThisDisplay->LocalVideoHeap0Info);
      }
  
      // 3D Heap manager not available.
      pThisDisplay->bDDHeapManager = FALSE;
  
      // Reset the driver version to 0 so it will be filled in again.
      pThisDisplay->dwDXVersion = 0;
  
      return TRUE;
  
  } // __DDE_bDestroyDDStructs
  
  //-----------------------------------------------------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // _DD_DDE_CreatePPDEV
  //
  // These functions are called in sync with the creation/destruction of the pDev
  //
  //-----------------------------------------------------------------------------
  BOOL 
  _DD_DDE_CreatePPDEV(
      PDEV* ppdev)
  {
      P3_THUNKEDDATA* pThisDisplay;
  
      DISPDBG((DBGLVL,"*** In _DD_DDE_CreatePPDEV"));
  
      ASSERTDD(ppdev->thunkData == NULL,
               "ERROR: thunkData already created for this pDev??");
  
      // initialize the DX context which will be used by the display driver 
      // context switcher. We need a reference count because there is a case 
      // when a second, temporary, context would otherwise be created (when 
      // enabling the second adapter in a m-monitor system), first scrubbing 
      // out the old context ID, then invalidating the new one when it is
      // deleted!
      ppdev->DDContextID = -1;
      ppdev->DDContextRefCount = 0;
  
      // Allocate our ppdev
      ppdev->thunkData = (PVOID)HEAP_ALLOC(HEAP_ZERO_MEMORY, 
                                           sizeof(P3_THUNKEDDATA),
                                           ALLOC_TAG_DX(D));                                          
      if (ppdev->thunkData == NULL)
      {
          DISPDBG((ERRLVL, "_DD_DDE_CreatePPDEV: thunkdata alloc failed"));
          return (FALSE);
      }
  
      // Our ppdev is called pThisDisplay
      pThisDisplay = (P3_THUNKEDDATA*) ppdev->thunkData;
      pThisDisplay->ppdev = ppdev;
  
      pThisDisplay->pGLInfo = (PVOID)HEAP_ALLOC(HEAP_ZERO_MEMORY, 
                                                sizeof(GlintInfo),
                                                ALLOC_TAG_DX(E));
      if (pThisDisplay->pGLInfo == NULL)
      {
          DISPDBG((ERRLVL, "_DD_DDE_CreatePPDEV: pGLInfo alloc failed"));
  
          EngFreeMem (pThisDisplay);
          ppdev->thunkData = NULL;
  
          return (FALSE);
      }
  
  //@@BEGIN_DDKSPLIT
      // W9X DX version is setup in the display driver.
  //@@END_DDKSPLIT    
  
      // On Windows W2000 DX is always at least DX7
      pThisDisplay->dwDXVersion = DX7_RUNTIME;
  
      GetChipInfoForDDraw(ppdev, 
                          &pThisDisplay->pGLInfo->dwRenderChipID, 
                          &pThisDisplay->pGLInfo->dwRenderChipRev, 
                          &pThisDisplay->pGLInfo->dwRenderFamily,
                          &pThisDisplay->pGLInfo->dwGammaRev);
  
      DISPDBG((DBGLVL,"RenderChip: 0x%x, RenderFamily: 0x%x", 
                      pThisDisplay->pGLInfo->dwRenderChipID, 
                      pThisDisplay->pGLInfo->dwRenderFamily));
  
      return TRUE;
  } // _DD_DDE_CreatePPDEV
  
  //-----------------------------------------------------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // _DD_DDE_ResetPPDEV
  //
  //-----------------------------------------------------------------------------
  void _DD_DDE_ResetPPDEV(PDEV* ppdevOld, PDEV* ppdevNew)
  {
      P3_THUNKEDDATA* pThisDisplayOld = (P3_THUNKEDDATA*)ppdevOld->thunkData;
      P3_THUNKEDDATA* pThisDisplayNew = (P3_THUNKEDDATA*)ppdevNew->thunkData;
      
      DISPDBG((DBGLVL,"_DD_DDE_ResetPPDEV: "
                      "pThisDispayOld: 0x%x, pThisDisplayNew: 0x%x", 
                      pThisDisplayOld, pThisDisplayNew));
                 
  } // _DD_DDE_ResetPPDEV
  
  //-----------------------------------------------------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // _DD_DDE_DestroyPPDEV
  //
  //-----------------------------------------------------------------------------
  void _DD_DDE_DestroyPPDEV(PDEV* ppdev)
  {
      P3_THUNKEDDATA* pThisDisplay = (P3_THUNKEDDATA*)ppdev->thunkData;
  
  #if DBG
      g_pThisTemp = NULL;
  #endif
  
      if (pThisDisplay)
      {
          // The 32 bit side will have allocated memory for use as global 
          // D3D/DD Driver data. Free it if it is there
          if (pThisDisplay->pD3DHALCallbacks16)
          {
              SHARED_HEAP_FREE(&pThisDisplay->pD3DHALCallbacks16, 
                               &pThisDisplay->pD3DHALCallbacks32,
                               TRUE);
                                  
              DISPDBG((DBGLVL,"Freed pThisDisplay->pD3DHALCallbacks32"));
          }
  
          if (pThisDisplay->pD3DDriverData16)
          {
              SHARED_HEAP_FREE(&pThisDisplay->pD3DDriverData16, 
                               &pThisDisplay->pD3DDriverData32,
                               TRUE);
                      
              DISPDBG((DBGLVL,"Freed pThisDisplay->pD3DDriverData32"));
          }
  
          pThisDisplay->lpD3DGlobalDriverData = 0;
          pThisDisplay->lpD3DHALCallbacks = 0;
  
          if (pThisDisplay->pGLInfo)
          {
              EngFreeMem (pThisDisplay->pGLInfo);
              pThisDisplay->pGLInfo = NULL;
              DISPDBG((DBGLVL,"Freed pThisDisplay->pGLInfo"));
          }
  
          EngFreeMem (pThisDisplay);
          pThisDisplay = NULL;
          DISPDBG((DBGLVL,"Freed pThisDisplay"));
      }
  
      // Clear the pointer
      ppdev->thunkData = NULL;
      
  } // _DD_DDE_DestroyPPDEV
  
  //-----------------------------------------------------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // _DD_DDE_vAssertModeDirectDraw
  //
  // This function is called by enable.c when entering or leaving the
  // DOS full-screen character mode.
  //
  //-----------------------------------------------------------------------------
  VOID 
  _DD_DDE_vAssertModeDirectDraw(
      PDEV*   ppdev,
      BOOL    bEnabled)
  {
      P3_THUNKEDDATA* pThisDisplay = (P3_THUNKEDDATA*)ppdev->thunkData;
      
      DISPDBG((DBGLVL, "_DD_DDE_vAssertModeDirectDraw: enter"));
  
  #if DX7_TEXMANAGEMENT
      // Mark all managed surfaces as dirty as we've lost 
      // everything living in the videomemory
  
     _DD_TM_EvictAllManagedTextures(pThisDisplay);
      
  #endif    
      
  } // _DD_DDE_vAssertModeDirectDraw
  
  //-----------------------------------------------------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // _DD_DDE_bEnableDirectDraw
  //
  // This function is called by enable.c when the mode is first initialized,
  // right after the miniport does the mode-set.
  //
  //-----------------------------------------------------------------------------
  BOOL _DD_DDE_bEnableDirectDraw(
  PDEV*   ppdev)
  {
      DISPDBG((DBGLVL, "_DD_DDE_bEnableDirectDraw: enter"));
  
      // DirectDraw is all set to be used on this card:
      ppdev->flStatus |= STAT_DIRECTDRAW;
  
      return(TRUE);
  } // _DD_DDE_bEnableDirectDraw
  
  //-----------------------------------------------------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // _DD_DDE_vDisableDirectDraw
  //
  // This function is called by enable.c when the driver is shutting down.
  //
  //-----------------------------------------------------------------------------
  VOID _DD_DDE_vDisableDirectDraw(
  PDEV*   ppdev)
  {
       DISPDBG((DBGLVL, "_DD_DDE_vDisableDirectDraw: enter"));
  } // _DD_DDE_vDisableDirectDraw
  
  //-----------------------------Public Routine----------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // DrvEnableDirectDraw
  //
  // Enables hardware for DirectDraw use.
  //
  // GDI calls DrvEnableDirectDraw to obtain pointers to the DirectDraw callbacks
  // that the driver supports. The driver should set the function pointer members 
  // of DD_CALLBACKS, DD_SURFACECALLBACKS, and DD_PALETTECALLBACKS to point to 
  // those functions that it implements. A driver should also set the 
  // corresponding bit fields in the dwFlags members of these structures for all 
  // supported callbacks.
  //
  // A driver's DrvEnableDirectDraw implementation can also dedicate hardware 
  // resources such as display memory for use by DirectDraw only.
  //
  // DrvEnableDirectDraw returns TRUE if it succeeds; otherwise, it returns FALSE
  //
  //  Parameters
  //
  //      dhpdev 
  //          Handle to the PDEV returned by the driver's DrvEnablePDEV routine.
  //      pCallBacks 
  //          Points to the DD_CALLBACKS structure to be initialized by the 
  //          driver. 
  //      pSurfaceCallBacks 
  //          Points to the DD_SURFACECALLBACKS structure to be initialized by 
  //          the driver. 
  //      pPaletteCallBacks 
  //          Points to the DD_PALETTECALLBACKS structure to be initialized by 
  //          the driver. 
  //
  //-----------------------------------------------------------------------------
  
  BOOL DrvEnableDirectDraw(
  DHPDEV                  dhpdev,
  DD_CALLBACKS*           pCallBacks,
  DD_SURFACECALLBACKS*    pSurfaceCallBacks,
  DD_PALETTECALLBACKS*    pPaletteCallBacks)
  {
      PDEV* ppdev;
      BOOL bRet;
      DWORD dwResult;
      P3_THUNKEDDATA* pThisDisplay;
      DWORD *theVBlankThing, *bOverlayEnabled;
      DWORD *VBLANKUpdateOverlay;
      DWORD *VBLANKUpdateOverlayWidth;
      DWORD *VBLANKUpdateOverlayHeight;
      DWORD Buffers;
      
      ppdev = (PDEV*) dhpdev;
      pThisDisplay = (P3_THUNKEDDATA*) ppdev->thunkData;
  
      if (!bSetupOffscreenForDDraw (FALSE, 
                                    ppdev, 
                                    &theVBlankThing, 
                                    &bOverlayEnabled, 
                                    &VBLANKUpdateOverlay, 
                                    &VBLANKUpdateOverlayWidth, 
                                    &VBLANKUpdateOverlayHeight))
      {
          DISPDBG((ERRLVL, "DrvEnableDirectDraw: "
                           "bSetupOffscreenForDDraw failed, but continuing"));
          //return (FALSE);
      }
  
      pThisDisplay->VBlankStatusPtr = theVBlankThing;
      pThisDisplay->bOverlayEnabled = bOverlayEnabled;
      pThisDisplay->bVBLANKUpdateOverlay = VBLANKUpdateOverlay;
      pThisDisplay->VBLANKUpdateOverlayWidth = VBLANKUpdateOverlayWidth;
      pThisDisplay->VBLANKUpdateOverlayHeight = VBLANKUpdateOverlayHeight;
  
  #if DBG
      // Read in the registry variable for the debug level
      {
          // Get the Debuglevel for DirectX
          bRet = GET_REGISTRY_ULONG_FROM_STRING("Direct3DHAL.Debug", &dwResult);
          if (bRet == TRUE)
          {
              P3R3DX_DebugLevel = (LONG)dwResult;
          }
          else
          {
              P3R3DX_DebugLevel = 0;
          }
  
          DISPDBG((WRNLVL,"Setting DebugLevel to 0x%x", P3R3DX_DebugLevel));
      }
  #endif
  
      // Create context with >2 sub-buffers for Interupt driven DMA.
      bRet =GET_REGISTRY_ULONG_FROM_STRING("Direct3DHAL.SubBuffers", &dwResult);
      if ((dwResult == 0) || (bRet == FALSE))
      {
          // Default
          Buffers = DEFAULT_SUBBUFFERS;
      }
      else 
      {
          if (dwResult > MAX_SUBBUFFERS) 
          {
              Buffers = MAX_SUBBUFFERS;
          }
          else
          {
              Buffers = dwResult;
          }
          
          if (Buffers < 2)
          {
              Buffers = 2;
          }
      }
  
      pThisDisplay->pGLInfo->dw3DDMABufferSize = 0;
      pThisDisplay->pGLInfo->dw3DDMABufferPhys = 0;
      pThisDisplay->pGLInfo->dw3DDMABufferVirt = 0;
  
      // Allocate a DMA Buffer on Win2K
      DDGetFreeDMABuffer(&pThisDisplay->pGLInfo->dw3DDMABufferPhys,
                         &pThisDisplay->pGLInfo->dw3DDMABufferVirt,
                         &pThisDisplay->pGLInfo->dw3DDMABufferSize);
  
      if (pThisDisplay->pGLInfo->dw3DDMABufferSize != 0)
      {
          DISPDBG((DBGLVL,"Allocated DMA Buffer:- "
                          "Phys:0x%x, Virt:0x%x, Size:0x%x",
                          pThisDisplay->pGLInfo->dw3DDMABufferPhys,
                          pThisDisplay->pGLInfo->dw3DDMABufferVirt,
                          pThisDisplay->pGLInfo->dw3DDMABufferSize));
      }
      else
      {
          DISPDBG((WRNLVL,"Failed to allocate DMA Buffer!"));
      }
  
      if(ppdev->DDContextID == -1)
      {
          // we don't have a DDraw context: create one now
          ppdev->DDContextID = GlintAllocateNewContext(ppdev, 
                                                       NULL, 
                                                       0, 
                                                       Buffers, 
                                                       NULL, 
                                                       ContextType_None);
          if(ppdev->DDContextID != -1)
          {
              ++ppdev->DDContextRefCount;
              
              DISPDBG((DBGLVL, "<%13s, %4d>: DrvEnableDirectDraw: "
                               "Created DDraw context, current DX context "
                               "count = %d for ppdev %p", 
                               __FILE__, __LINE__, 
                               ppdev->DDContextRefCount, ppdev));
          }
      }
      
      if (ppdev->DDContextID < 0) 
      {
          DISPDBG((ERRLVL, "ERROR: failed to allocate DDRAW context"));
          return(FALSE);
      }
      
      DISPDBG((DBGLVL,"  Created DD Register context: 0x%x", 
                      ppdev->DDContextID));
  
      if (!__DDE_bSetupDDStructs (pThisDisplay, TRUE))
      {
          vGlintFreeContext (ppdev, ppdev->DDContextID);
          DISPDBG((ERRLVL, "ERROR: DrvEnableDirectDraw: "
                           "__DDE_bSetupDDStructs failed"));
          return (FALSE);
      }
      
      if (!_DD_InitDDHAL32Bit (pThisDisplay))
      {
          vGlintFreeContext (ppdev, ppdev->DDContextID);
          DISPDBG((ERRLVL, "ERROR: DrvEnableDirectDraw: "
                           "_DD_InitDDHAL32Bit failed"));
          return (FALSE);
      }
      
      // Set the flag that says we have to handle a mode change.
      // This will cause the chip to be initialised properly at the 
      // right time.
      pThisDisplay->bResetMode = TRUE;
      pThisDisplay->bStartOfDay = TRUE;
      pThisDisplay->pGLInfo->dwDirectXState = DIRECTX_LASTOP_UNKNOWN;
  
      // Fill in the function pointers at start of day.  We copy these from 
      // the Initialisation done in _DD_InitDDHAL32Bit.  It's OK to do this 
      // because on a Windows NT compile the structures should match
      memcpy(pCallBacks, 
             &pThisDisplay->DDHALCallbacks, 
             sizeof(DD_CALLBACKS));
             
      memcpy(pSurfaceCallBacks, 
             &pThisDisplay->DDSurfCallbacks, 
             sizeof(DD_SURFACECALLBACKS));
  
      // Note that we don't call 'vGetDisplayDuration' here, for a couple of
      // reasons:
      //
      //  o Because the system is already running, it would be disconcerting
      //    to pause the graphics for a good portion of a second just to read
      //    the refresh rate;
      //  o More importantly, we may not be in graphics mode right now.
      //
      // For both reasons, we always measure the refresh rate when we switch
      // to a new mode.
  
      return(TRUE);
      
  } // DrvEnableDirectDraw
  
  //-----------------------------Public Routine----------------------------------
  //
  // ***************************WIN NT ONLY**********************************
  //
  // DrvDisableDirectDraw
  //
  // Disables hardware for DirectDraw use.
  //
  // GDI calls DrvDisableDirectDraw when the last DirectDraw application has 
  // finished running. A driver's DrvDisableDirectDraw implementation should 
  // clean up any software resources and reclaim any hardware resources that 
  // the driver dedicated to DirectDraw in DrvEnableDirectDraw.
  //
  // Parameters
  //      dhpdev 
  //          Handle to the PDEV that was returned by the driver's 
  //          DrvEnablePDEV routine. 
  //
  //-----------------------------------------------------------------------------
  VOID 
  DrvDisableDirectDraw(
      DHPDEV      dhpdev)
  {
      PDEV* ppdev;
      P3_THUNKEDDATA* pThisDisplay;
  
      ppdev = (PDEV*) dhpdev;
      pThisDisplay = (P3_THUNKEDDATA*) ppdev->thunkData;
  
      // Only do all this stuff if we have not already been disabled.
      // Note that when running NT4 without SP3, this function can be called
      // more times than DrvEnableDirectDraw.
      if (pThisDisplay != NULL)
      {
          // Re-enable GDI off-screen bitmaps
          (void) bSetupOffscreenForDDraw (TRUE, 
                                          ppdev, 
                                          NULL, 
                                          NULL, 
                                          NULL, 
                                          NULL, 
                                          NULL);
  
          // Free all memory
          (void) __DDE_bDestroyDDStructs (pThisDisplay);
  
          if(ppdev->DDContextRefCount > 0)
          {
              if(--ppdev->DDContextRefCount == 0)
              {
                  vGlintFreeContext (ppdev, ppdev->DDContextID);
                  DISPDBG((DBGLVL,"Freed DDraw context: 0x%x", 
                                  ppdev->DDContextID));
                                  
                  ppdev->DDContextID = -1;
  
                  DISPDBG((DBGLVL, "<%13s, %4d>: DrvDisableDirectDraw:"
                                   " Deleted DDraw context, current DX context"
                                   " count = %d for ppdev %p", 
                                   __FILE__, __LINE__, 
                                   ppdev->DDContextRefCount, ppdev));
              }
          }
  
          DDFreeDMABuffer((void*)(ULONG_PTR)pThisDisplay->pGLInfo->dw3DDMABufferPhys);
  
      }
  } // DrvDisableDirectDraw
  
  #endif  //  WNT_DDRAW
  