Index: trunk/src/VBox/Additions/WINNT/Graphics/Display/dd.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Display/dd.c	(revision 3902)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Display/dd.c	(revision 4027)
@@ -16,5 +16,5 @@
 
 #ifdef DEBUG
-#define LOG_ENABLED
+#define LOG_ENABLED 1
 #endif
 
@@ -65,4 +65,7 @@
 {
     PPDEV pDev = (PPDEV)dhpdev;
+    BOOL bDefineDDrawHeap = FALSE;
+    DWORD cHeaps = 0;
+    VIDEOMEMORY *pVm = NULL;
 
     DISPDBG((0, "%s: %p, %p, %p, %p, %p. %p\n", __FUNCTION__, dhpdev, pHalInfo, pdwNumHeaps, pvmList, pdwNumFourCCCodes, pdwFourCC));
@@ -77,4 +80,17 @@
     if (!(pvmList && pdwFourCC)) 
     {
+        memset(&pHalInfo->ddCaps, 0, sizeof(DDNTCORECAPS));
+        pHalInfo->ddCaps.dwSize         = sizeof(DDNTCORECAPS);
+        pHalInfo->ddCaps.dwVidMemTotal  = pDev->cScreenSize - pDev->cFrameBufferSize;
+        pHalInfo->ddCaps.dwVidMemFree   = pHalInfo->ddCaps.dwVidMemTotal;
+
+        pHalInfo->ddCaps.dwCaps         = 0;
+        pHalInfo->ddCaps.dwCaps2        = 0;
+
+        /* Declare we can handle textures wider than the primary */
+        pHalInfo->ddCaps.dwCaps2 |= DDCAPS2_WIDESURFACES;
+
+        pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+        
         /* Create primary surface attributes */
         pHalInfo->vmiData.pvPrimary                 = pDev->pjScreen;
@@ -108,16 +124,45 @@
         pHalInfo->vmiData.dwTextureAlign            = 4;
     }
-    memset(&pHalInfo->ddCaps, 0, sizeof(DDNTCORECAPS));
-    pHalInfo->ddCaps.dwSize         = sizeof(DDNTCORECAPS);
-    pHalInfo->ddCaps.dwVidMemTotal  = pDev->cScreenSize;
-    pHalInfo->ddCaps.dwVidMemFree   = pDev->cScreenSize;
-
-    pHalInfo->ddCaps.dwCaps         = 0;
-    pHalInfo->ddCaps.dwCaps2        = 0;
-
-    /* Declare we can handle textures wider than the primary */
-    pHalInfo->ddCaps.dwCaps2 |= DDCAPS2_WIDESURFACES;
-
-    pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+    
+    cHeaps = 0;
+
+    /* Do we have sufficient videomemory to create an off-screen heap for DDraw? */
+    if (pDev->cScreenSize > pDev->cFrameBufferSize)
+    {
+        bDefineDDrawHeap = TRUE;
+        cHeaps++;
+    }
+
+    pDev->cHeaps = cHeaps;
+    *pdwNumHeaps  = cHeaps;
+
+    // If pvmList is not NULL then we can go ahead and fill out the VIDEOMEMORY
+    // structures which define our requested heaps.
+
+    if(pvmList) {
+
+        pVm=pvmList;
+
+        //
+        // Snag a pointer to the video-memory list so that we can use it to
+        // call back to DirectDraw to allocate video memory:
+        //
+        pDev->pvmList = pVm;
+
+        //
+        // Define the heap for DirectDraw
+        //
+        if ( bDefineDDrawHeap )
+        {
+            pVm->dwFlags        = VIDMEM_ISLINEAR ;
+            pVm->fpStart        = pDev->cFrameBufferSize;
+            pVm->fpEnd          = pDev->cScreenSize;
+
+            pVm->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+            DISPDBG((0, "fpStart %ld fpEnd %ld\n", pVm->fpStart, pVm->fpEnd));
+
+            pVm++;
+        }
+    }
 
 #if 0 /* not mandatory */
@@ -172,13 +217,11 @@
     pCallBacks->dwFlags               = 0;
 
-    /*
     pCallBacks->dwFlags               = DDHAL_CB32_CREATESURFACE | DDHAL_CB32_CANCREATESURFACE;
     pCallBacks->CreateSurface         = DdCreateSurface;
     pCallBacks->CanCreateSurface      = DdCanCreateSurface;
-    pCallBacks->WaitForVerticalBlank  = DdWaitForVerticalBlank;
-    pCallBacks->GetScanLine           = DdGetScanLine;
-    pCallBacks->MapMemory             = DdMapMemory;
-    DDHAL_CB32_WAITFORVERTICALBLANK | DDHAL_CB32_MAPMEMORY | DDHAL_CB32_GETSCANLINE 
-    */
+    // pCallBacks->WaitForVerticalBlank  = DdWaitForVerticalBlank;
+    // pCallBacks->GetScanLine           = DdGetScanLine;
+    // pCallBacks->MapMemory             = DdMapMemory;
+    // DDHAL_CB32_WAITFORVERTICALBLANK | DDHAL_CB32_MAPMEMORY | DDHAL_CB32_GETSCANLINE 
     /* Note: pCallBacks->SetMode & pCallBacks->DestroyDriver are unused in Windows 2000 and up */
 
@@ -652,5 +695,5 @@
     DISPDBG((0, "%s: %p\n", __FUNCTION__, pDev));
 
-    // remember setting of exclusive mode in ppdev,
+    // remember setting of exclusive mode in pDev,
     // so GDI can stop to promote DeviceBitmaps into
     // video memory
Index: trunk/src/VBox/Additions/WINNT/Graphics/Display/debug.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Display/debug.c	(revision 3902)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Display/debug.c	(revision 4027)
@@ -15,5 +15,5 @@
 #include "driver.h"
 
-#ifdef DEBUG
+#ifdef LOG_ENABLED
 
 #ifdef VBOX
Index: trunk/src/VBox/Additions/WINNT/Graphics/Display/driver.h
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Display/driver.h	(revision 3902)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Display/driver.h	(revision 4027)
@@ -70,4 +70,5 @@
     ULONG   cScreenSize;                // size of video memory, including
                                         // offscreen memory.
+    ULONG   cFrameBufferSize;           // size of screen video memory
     PVOID   pOffscreenList;             // linked list of DCI offscreen surfaces.
     FLONG   flRed;                      // For bitfields device, Red Mask
@@ -98,7 +99,10 @@
     VBOXDISPLAYINFO *pInfo;
     ULONG iDevice;
+    ULONG cbDisplayInformation;
 #ifdef VBOX_WITH_DDRAW
     BOOL             bDdExclusiveMode;
     DWORD            dwNewDDSurfaceOffset;
+    DWORD            cHeaps;
+    VIDEOMEMORY*     pvmList;
 #endif
 };
Index: trunk/src/VBox/Additions/WINNT/Graphics/Display/enable.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Display/enable.c	(revision 3902)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Display/enable.c	(revision 4027)
@@ -13,5 +13,5 @@
 \**************************************************************************/
 #ifdef DEBUG
-#define LOG_ENABLED
+#define LOG_ENABLED 1
 #endif
 
@@ -1000,7 +1000,7 @@
 {
     PPDEV               pDev = (PPDEV)pDirectDraw->dhpdev;
-    HBITMAP             hbmDevice;
+//    HBITMAP             hbmDevice;
     DD_SURFACE_GLOBAL*  pSurfaceGlobal;
-    SIZEL               sizl;
+//    SIZEL               sizl;
 
     DISPDBG((0, "%s: %p\n", __FUNCTION__, pDev));
Index: trunk/src/VBox/Additions/WINNT/Graphics/Display/screen.c
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Display/screen.c	(revision 3902)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Display/screen.c	(revision 4027)
@@ -66,8 +66,10 @@
                  DispInfo.u32DisplayInfoSize, pMemoryInformation->VideoRamLength));
         ppdev->pInfo = NULL;
+        ppdev->cbDisplayInformation = 0;
         return;
     }
     
     ppdev->iDevice = DispInfo.iDevice;
+    ppdev->cbDisplayInformation = DispInfo.u32DisplayInfoSize;
 
     pu8 = (uint8_t *)pMemoryInformation->VideoRamBase;
@@ -195,6 +197,4 @@
         }
 
-        ppdev->cScreenSize = videoMemoryInformation.VideoRamLength;
-        
         //
         // Initialize the head of the offscreen list to NULL.
@@ -246,4 +246,7 @@
         /* Setup the display information. */
         vboxSetupDisplayInfo (ppdev, &videoMemoryInformation);
+        
+        ppdev->cScreenSize = videoMemoryInformation.VideoRamLength - ppdev->cbDisplayInformation;
+        ppdev->cFrameBufferSize = videoMemoryInformation.FrameBufferLength;
     }
 
Index: trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideo.cpp
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideo.cpp	(revision 3902)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideo.cpp	(revision 4027)
@@ -43,7 +43,4 @@
 static WCHAR VBoxBiosString[] = L"Version 0xB0C2 or later";
 
-/* Number of reported monitors. Defaults to 1 (no DualView) */
-static int gNumDisplays = 1;
-
 /*
  * Globals for the last custom resolution set. This is important
@@ -197,5 +194,5 @@
 
     /* size of the VRAM in bytes */
-    ULONG vramSize = DeviceExtension->ulMaxFrameBufferSize;
+    ULONG vramSize = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
 
     gNumVideoModes = 0;
@@ -700,21 +697,21 @@
 
 /* Computes the size of a framebuffer. DualView has a few framebuffers of the computed size. */
-static ULONG VBoxVideoComputeMaxFrameBufferSize (ULONG AdapterMemorySize)
-{
-    /* The VRAM layout: 
-     *     Last 4096 bytes - Adapter information area.
-     *     Slack - what left after dividing the VRAM.
-     *     4096 bytes aligned framebuffers:
-     *       last 4096 bytes of each framebuffer is the display information area.
-     */
+static void vboxComputeFrameBufferSizes (PDEVICE_EXTENSION PrimaryExtension)
+{
+    ULONG ulAvailable = PrimaryExtension->u.primary.cbVRAM
+                        - PrimaryExtension->u.primary.cbMiniportHeap
+                        - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
 
     /* Size of a framebuffer. */
-    ULONG ulSize = (AdapterMemorySize - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE) / gNumDisplays;
+    
+    ULONG ulSize = ulAvailable / PrimaryExtension->u.primary.cDisplays;
     
     /* Align down to 4096 bytes. */
     ulSize &= ~0xFFF;
     
-    dprintf(("VBoxVideo::VBoxVideoComputeMaxFrameBufferSize: AdapterMemorySize = 0x%08X, gNumDisplays = %d, ulSize = 0x%08X, ulSize * gNumDisplays = 0x%08X, slack = 0x%08X\n",
-             AdapterMemorySize, gNumDisplays, ulSize, ulSize * gNumDisplays, (AdapterMemorySize - 4096) - ulSize * gNumDisplays));
+    dprintf(("VBoxVideo::vboxComputeFrameBufferSizes: cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X\n",
+             PrimaryExtension->u.primary.cbVRAM, PrimaryExtension->u.primary.cDisplays,
+             ulSize, ulSize * PrimaryExtension->u.primary.cDisplays,
+             ulAvailable - ulSize * PrimaryExtension->u.primary.cDisplays));
     
     if (ulSize > VBOX_VIDEO_DISPLAY_INFORMATION_SIZE)
@@ -725,55 +722,85 @@
     else
     {
+        /* Should not really get here. But still do it safely. */
         ulSize = 0;
     }
     
-    return ulSize;
-}
-
-static VOID VBoxMapAdapterInfo (PDEVICE_EXTENSION PrimaryExtension, ULONG AdapterMemorySize)
-{
+    /* Update the primary info. */
+    PrimaryExtension->u.primary.ulMaxFrameBufferSize     = ulSize;
+    PrimaryExtension->u.primary.ulDisplayInformationSize = VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
+    
+    /* Update the per extension info. */
+    PDEVICE_EXTENSION Extension = PrimaryExtension;
+    ULONG ulFrameBufferOffset = 0;
+    while (Extension)
+    {
+        Extension->ulFrameBufferOffset = ulFrameBufferOffset;
+        /* That is assigned when a video mode is set. */
+        Extension->ulFrameBufferSize = 0;
+        
+        dprintf(("VBoxVideo::vboxComputeFrameBufferSizes: [%d] ulFrameBufferOffset 0x%08X\n",
+                 ulFrameBufferOffset));
+        
+        ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize
+                               + PrimaryExtension->u.primary.ulDisplayInformationSize;
+                               
+        Extension = Extension->pNext;
+    }
+}
+
+static int vboxMapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension)
+{
+    dprintf(("VBoxVideo::vboxMapAdapterMemory\n"));
+
     PHYSICAL_ADDRESS FrameBuffer;
+    FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS
+                           + PrimaryExtension->u.primary.cbVRAM
+                           - PrimaryExtension->u.primary.cbMiniportHeap
+                           - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
+
+    PVOID VideoRamBase = NULL;
     ULONG inIoSpace = 0;
-    VP_STATUS Status;
-
-    dprintf(("VBoxVideo::VBoxSetupAdapterInfo\n"));
-
-    FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + AdapterMemorySize - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
-
-    PVOID VideoRamBase = NULL;
-    ULONG VideoRamLength = VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
-
-    Status = VideoPortMapMemory(PrimaryExtension, FrameBuffer,
-       &VideoRamLength, &inIoSpace,
-       &VideoRamBase);
+    ULONG VideoRamLength = PrimaryExtension->u.primary.cbMiniportHeap
+                           + VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
+
+    VP_STATUS Status = VideoPortMapMemory (PrimaryExtension, FrameBuffer,
+                                           &VideoRamLength, &inIoSpace,
+                                           &VideoRamBase);
 
     if (Status == NO_ERROR)
     {
-        PrimaryExtension->AdapterInformation = VideoRamBase;
-    }
-    else
-    {
-        PrimaryExtension->AdapterInformation = NULL;
-    }
-}
-
-static VOID VBoxSetupAdapterInfo (PDEVICE_EXTENSION PrimaryExtension)
-{
-    if (!PrimaryExtension->AdapterInformation)
-    {
-        return;
+        PrimaryExtension->u.primary.pvMiniportHeap       = VideoRamBase;
+        PrimaryExtension->u.primary.pvAdapterInformation = (uint8_t *)VideoRamBase
+                                                           + PrimaryExtension->u.primary.cbMiniportHeap;
     }
     
-    /* That dublicates the code in VBoxSetupDisplays, better would be to have 
-     * linked list of device extestions and fill the adapter memory with
-     * information from these extension structures.
-     */
-    uint8_t *pu8 = (uint8_t *)PrimaryExtension->AdapterInformation;
-    uint32_t u32Offset = 0;
+    dprintf(("VBoxVideo::vboxMapAdapterMemory rc = %d\n", Status));
+    
+    return Status;
+}
+
+static void vboxUnmapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension)
+{
+    dprintf(("VBoxVideo::vboxMapAdapterMemory\n"));
+    
+    if (PrimaryExtension->u.primary.pvMiniportHeap)
+    {
+        VideoPortUnmapMemory(PrimaryExtension, PrimaryExtension->u.primary.pvMiniportHeap, NULL);
+    }
+    
+    PrimaryExtension->u.primary.pvMiniportHeap       = NULL;
+    PrimaryExtension->u.primary.pvAdapterInformation = NULL;
+}
+
+static void vboxSetupAdapterInfo (PDEVICE_EXTENSION PrimaryExtension)
+{
+    dprintf(("VBoxVideo::vboxSetupAdapterInfo\n"));
     
     VBOXVIDEOINFOHDR *pHdr;
-    int iDisplay;
-
-    for (iDisplay = 0; iDisplay < gNumDisplays; ++iDisplay)
+
+    uint8_t *pu8 = (uint8_t *)PrimaryExtension->u.primary.pvAdapterInformation;
+
+    PDEVICE_EXTENSION Extension = PrimaryExtension;
+    while (Extension)
     {
         pHdr = (VBOXVIDEOINFOHDR *)pu8;
@@ -787,12 +814,31 @@
         pu8 += sizeof (VBOXVIDEOINFODISPLAY);
 
-        pDisplay->u32Index           = iDisplay;
-        pDisplay->u32Offset          = u32Offset;
-        pDisplay->u32FramebufferSize = PrimaryExtension->ulMaxFrameBufferSize;
-        pDisplay->u32InformationSize = VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
+        pDisplay->u32Index           = Extension->iDevice;
+        pDisplay->u32Offset          = Extension->ulFrameBufferOffset;
+        pDisplay->u32FramebufferSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
+        pDisplay->u32InformationSize = PrimaryExtension->u.primary.ulDisplayInformationSize;
+
+        Extension = Extension->pNext;
+    }
+
+    
+    /* The heap description. */
+    pHdr = (VBOXVIDEOINFOHDR *)pu8;
+    pu8 += sizeof (VBOXVIDEOINFOHDR);
+
+    pHdr->u8Type     = VBOX_VIDEO_INFO_TYPE_NV_HEAP;
+    pHdr->u8Reserved = 0;
+    pHdr->u16Length  = sizeof (VBOXVIDEOINFONVHEAP);
+
+    VBOXVIDEOINFONVHEAP *pHeap = (VBOXVIDEOINFONVHEAP *)pu8;
+    pu8 += sizeof (VBOXVIDEOINFONVHEAP);
+
+    pHeap->u32HeapOffset = PrimaryExtension->u.primary.cbVRAM 
+                           - PrimaryExtension->u.primary.cbMiniportHeap
+                           - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
+    pHeap->u32HeapSize = PrimaryExtension->u.primary.cbMiniportHeap;
         
-        u32Offset += PrimaryExtension->ulMaxFrameBufferSize + VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
-    }
-
+    
+    /* The END marker. */
     pHdr = (VBOXVIDEOINFOHDR *)pu8;
     pu8 += sizeof (VBOXVIDEOINFOHDR);
@@ -803,6 +849,8 @@
 
     /* Inform the host about the display configuration. */
-    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_CMONITORS);
+    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
     VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY);
+    
+    dprintf(("VBoxVideo::vboxSetupAdapterInfo finished\n"));
 }
 
@@ -812,93 +860,158 @@
  * intentionally crippled.
  */
-VOID VBoxSetupDisplays(PDEVICE_EXTENSION PrimaryExtension, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
-{
-   typedef VP_STATUS (*pCreateSecDisp)(PVOID, PVOID *, ULONG);
-   pCreateSecDisp pVPCreateSecDisp;
-   PVOID pFunc;
-   int iDisplay;
-   VP_STATUS rc;
-   PDEVICE_EXTENSION pSecExt;
-   ULONG AdapterMemorySize;
-
-   dprintf(("VBoxVideo::VBoxRegisterSecondaryDisplays: PrimaryExtension = %p\n", PrimaryExtension));
-
-   AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
-
-   /* Initialize DualView related stuff in device extension for 1 monitor (must be done always!).
-    * Assume that the is no dual view and initialize the maximum possible frame buffer size.
-    * Also assume no VBox extension support.
-    */
-   PrimaryExtension->iDevice      = 0;
-   PrimaryExtension->pvPrimaryExt = PrimaryExtension;
-
-   PrimaryExtension->ulFrameBufferOffset = 0;
-   PrimaryExtension->ulMaxFrameBufferSize = AdapterMemorySize -
-                                            VBOX_VIDEO_ADAPTER_INFORMATION_SIZE -
-                                            VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
-   PrimaryExtension->bDualViewSupported = FALSE;
-   PrimaryExtension->AdapterInformation = NULL;
-   
-   /* Verify that the HW support VirtualBox extensions. */
-   VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
-   VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_VBOX_VIDEO);
-   if (VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA) != VBE_DISPI_ID_VBOX_VIDEO)
-   {
-       dprintf(("VBoxVideo::VBoxSetupDisplays: virtual hardware do not support VBox extensions!!!\n"));
-       return;
-   }
-
-   /* Map the adapter information memory. */
-   VBoxMapAdapterInfo (PrimaryExtension, AdapterMemorySize);
-   
-   if (!PrimaryExtension->AdapterInformation)
-   {
-       dprintf(("VBoxVideo::VBoxSetupDisplays: failed to map adapter memory!!!\n"));
-       return;
-   }
-
-   /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
-   if (vboxQueryWinVersion() <= WINNT4) 
-   {
-       pFunc = NULL;
-   } 
-   else 
-   {
-       /* This bluescreens on NT4, hence the above version check */
-       pFunc = (pConfigInfo->VideoPortGetProcAddress)(PrimaryExtension,
-                                                      (PUCHAR)"VideoPortCreateSecondaryDisplay");
-   }
-
-   if (pFunc != NULL) {
-      pVPCreateSecDisp = (pCreateSecDisp)pFunc;
-
-      /* Query the configured number of displays */
-      VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_CMONITORS);
-      gNumDisplays = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
-      dprintf(("VBoxVideo::VBoxRegisterSecondaryDisplays: gNumDisplays = %d\n", gNumDisplays));
-
-      PrimaryExtension->bDualViewSupported = (gNumDisplays != 0);
-
-      /* Now when the number of monitors is known, update the maximum size. */
-      PrimaryExtension->ulMaxFrameBufferSize = VBoxVideoComputeMaxFrameBufferSize (AdapterMemorySize);
-
-      for (iDisplay = 1; iDisplay < gNumDisplays; ++iDisplay)
-      {
-         rc = pVPCreateSecDisp(PrimaryExtension, (PVOID*)&pSecExt, VIDEO_DUALVIEW_REMOVABLE);
-         dprintf(("VBoxVideo::VBoxRegisterSecondaryDisplays: VideoPortCreateSecondaryDisplay returned %#x, pSecExt = %p\n", rc, pSecExt));
-         if (rc != NO_ERROR)   /* Failure to create secondary displays is not fatal */
-            break;
-
-         pSecExt->iDevice = iDisplay;
-         pSecExt->pvPrimaryExt = PrimaryExtension;
-
-         pSecExt->ulFrameBufferOffset = iDisplay * (PrimaryExtension->ulMaxFrameBufferSize + VBOX_VIDEO_DISPLAY_INFORMATION_SIZE);
-         pSecExt->ulMaxFrameBufferSize = PrimaryExtension->ulMaxFrameBufferSize;
-         pSecExt->bDualViewSupported = PrimaryExtension->bDualViewSupported;
-         pSecExt->AdapterInformation = PrimaryExtension->AdapterInformation;
-      }
-   }
-
-   VBoxSetupAdapterInfo (PrimaryExtension);
+VOID VBoxSetupDisplays(PDEVICE_EXTENSION PrimaryExtension, PVIDEO_PORT_CONFIG_INFO pConfigInfo, ULONG AdapterMemorySize)
+{
+    VP_STATUS rc = NO_ERROR;
+
+    dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
+             PrimaryExtension));
+
+    /* Preinitialize the primary extension. */
+    PrimaryExtension->pNext                              = NULL;
+    PrimaryExtension->pPrimary                           = PrimaryExtension;
+    PrimaryExtension->iDevice                            = 0;
+    PrimaryExtension->ulFrameBufferOffset                = 0;
+    PrimaryExtension->ulFrameBufferSize                  = 0;
+    PrimaryExtension->u.primary.ulVbvaEnabled            = 0;
+    PrimaryExtension->u.primary.bVBoxVideoSupported      = FALSE;
+    PrimaryExtension->u.primary.cDisplays                = 1;
+    PrimaryExtension->u.primary.cbVRAM                   = AdapterMemorySize;
+    PrimaryExtension->u.primary.cbMiniportHeap           = 0;
+    PrimaryExtension->u.primary.pvMiniportHeap           = NULL;
+    PrimaryExtension->u.primary.pvAdapterInformation     = NULL;
+    PrimaryExtension->u.primary.ulMaxFrameBufferSize     = 0;
+    PrimaryExtension->u.primary.ulDisplayInformationSize = 0;
+
+    
+    /* Verify whether the HW supports VirtualBox extensions. */
+    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
+    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA,  VBE_DISPI_ID_VBOX_VIDEO);
+
+    if (VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA) == VBE_DISPI_ID_VBOX_VIDEO)
+    {
+        PrimaryExtension->u.primary.bVBoxVideoSupported = TRUE;
+    }
+    
+    dprintf(("VBoxVideo::VBoxSetupDisplays: bVBoxVideoSupported = %d\n",
+             PrimaryExtension->u.primary.bVBoxVideoSupported));
+    
+    /* Setup the non-volatile heap and the adapter memory. */
+    if (PrimaryExtension->u.primary.bVBoxVideoSupported)
+    {
+        /* Query the size of the non-volatile heap. */
+        VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
+        VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_QUERY_OFFSCREEN_HEAP_SIZE);
+        
+        ULONG cbMiniportHeap = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
+        
+        /* Do not allow too big heap. 50% of VRAM should be enough. */
+        ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 2 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
+        
+        if (cbMiniportHeap > cbMiniportHeapMaxSize)
+        {
+            cbMiniportHeap = cbMiniportHeapMaxSize;
+        }
+        
+        /* Round up to 4096. */
+        PrimaryExtension->u.primary.cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
+        
+        dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
+                 cbMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap, cbMiniportHeapMaxSize));
+        
+        /* Map the heap region and the adapter information area.
+         *
+         * Note: the heap will be used by display drivers, possibly by a few instances
+         *       in multimonitor configuration, but the memory is mapped here ones.
+         *       It is assumed that all display drivers and the miniport has the SAME
+         *       virtual address space.
+         * 
+         */
+        rc = vboxMapAdapterMemory (PrimaryExtension);
+        
+        if (rc != NO_ERROR)
+        {
+            PrimaryExtension->u.primary.cbMiniportHeap = 0;
+            PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
+        }
+    }
+
+    /* Check whether the guest supports multimonitors. */
+    if (PrimaryExtension->u.primary.bVBoxVideoSupported)
+    {
+        typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
+        PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
+        
+        /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
+        if (vboxQueryWinVersion() > WINNT4) 
+        {
+            /* This bluescreens on NT4, hence the above version check */
+            pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
+                                                                       (PrimaryExtension,
+                                                                        (PUCHAR)"VideoPortCreateSecondaryDisplay");
+        }
+
+        if (pfnCreateSecondaryDisplay != NULL)
+        {
+            /* Query the configured number of displays. */
+            VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
+            int cDisplays = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
+            
+            dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
+                     cDisplays));
+                     
+            if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
+            {
+                /* Host reported some bad value. Continue in the 1 screen mode. */
+                cDisplays = 1;
+            }
+
+            PDEVICE_EXTENSION pPrev = PrimaryExtension;
+            
+            int iDisplay;
+            for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
+            {
+               PDEVICE_EXTENSION SecondaryExtension = NULL;
+               rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
+               
+               dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
+                        rc, SecondaryExtension));
+               
+               if (rc != NO_ERROR)
+               {
+                   break;
+               }
+
+               SecondaryExtension->pNext                = NULL;
+               SecondaryExtension->pPrimary             = PrimaryExtension;
+               SecondaryExtension->iDevice              = iDisplay;
+               SecondaryExtension->ulFrameBufferOffset  = 0;
+               SecondaryExtension->ulFrameBufferSize    = 0;
+               SecondaryExtension->u.secondary.bEnabled = FALSE;
+               
+               /* Update the list pointers. */
+               pPrev->pNext = SecondaryExtension;
+               pPrev = SecondaryExtension;
+               
+               /* Take the successfully created display into account. */
+               PrimaryExtension->u.primary.cDisplays++;
+            }
+            
+            /* Failure to create secondary displays is not fatal */
+            rc = NO_ERROR;
+        }
+    }
+        
+    /* Now when the number of monitors is known and extensions are created,
+     * calculate the layout of framebuffers.
+     */
+    vboxComputeFrameBufferSizes (PrimaryExtension);
+
+    if (PrimaryExtension->u.primary.bVBoxVideoSupported)
+    {
+        /* Setup the information for the host. */
+        vboxSetupAdapterInfo (PrimaryExtension);
+    }
+    
+    dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
 }
 
@@ -983,6 +1096,6 @@
       dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
 
-      /* Attempt to register secondary displays */
-      VBoxSetupDisplays((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo);
+      /* Setup the Device Extension and if possible secondary displays. */
+      VBoxSetupDisplays((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
 
       // pretend success to make the driver work.
@@ -1012,5 +1125,5 @@
 
     /* Initialize the request pointer. */
-    pDevExt->pvReqFlush = NULL;
+    pDevExt->u.primary.pvReqFlush = NULL;
 
     /*
@@ -1371,7 +1484,10 @@
 
             ulAttach = *((PULONG)RequestPacket->InputBuffer);
-            dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW (%ld)\n", ulAttach));
-
-            pDevExt->bEnabled = (BOOLEAN)ulAttach;
+            dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
+
+            if (pDevExt->iDevice > 0)
+            {
+                pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
+            }
             Result = TRUE;
             break;
@@ -1382,8 +1498,8 @@
             dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
 
-            if (pDevExt->bDualViewSupported)
+            if (pDevExt->pPrimary->u.primary.bVBoxVideoSupported)
             {
                 /* The display driver must have prepared the monitor information. */
-                VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_CMONITORS);
+                VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
                 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE + pDevExt->iDevice);
             }
@@ -1392,5 +1508,5 @@
                 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
             }
-            Result = pDevExt->bDualViewSupported;
+            Result = pDevExt->pPrimary->u.primary.bVBoxVideoSupported;
             break;
         }
@@ -1411,5 +1527,5 @@
             
             pDispInfo->iDevice = pDevExt->iDevice;
-            pDispInfo->u32DisplayInfoSize = VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
+            pDispInfo->u32DisplayInfoSize = pDevExt->pPrimary->u.primary.ulDisplayInformationSize;
 
             RequestPacket->StatusBlock->Information = sizeof(QUERYDISPLAYINFORESULT);
@@ -1543,11 +1659,13 @@
     VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
 
-    if (pDevExt->pvReqFlush != NULL)
-    {
-        VbglGRFree ((VMMDevRequestHeader *)pDevExt->pvReqFlush);
-        pDevExt->pvReqFlush = NULL;
+    if (pDevExt->u.primary.pvReqFlush != NULL)
+    {
+        VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
+        pDevExt->u.primary.pvReqFlush = NULL;
     }
 
     VbglTerminate ();
+    
+    vboxUnmapAdapterMemory (pDevExt);
 
     return TRUE;
@@ -1669,5 +1787,6 @@
 
     MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
-    MapInformation->VideoRamLength = DeviceExtension->ulMaxFrameBufferSize + VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
+    MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize
+                                     + DeviceExtension->pPrimary->u.primary.ulDisplayInformationSize;
 
     Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
@@ -1802,6 +1921,6 @@
    PULONG pUnused)
 {
-   dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
-            HwDeviceExtension, ChildEnumInfo));
+    dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
+             HwDeviceExtension, ChildEnumInfo));
 
     DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
@@ -1809,7 +1928,5 @@
     if (ChildEnumInfo->ChildIndex > 0)
     {
-        if (   (ChildEnumInfo->ChildIndex == 1 && gNumDisplays == 0)
-            || ((int)ChildEnumInfo->ChildIndex <= gNumDisplays)
-           )
+        if ((int)ChildEnumInfo->ChildIndex <= pDevExt->pPrimary->u.primary.cDisplays)
         {
             *VideoChildType = Monitor;
@@ -1827,9 +1944,9 @@
 {
     DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
-    DEVICE_EXTENSION *pPrimaryDevExt = (DEVICE_EXTENSION *)(pDevExt? pDevExt->pvPrimaryExt: NULL);
+    DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
 
     if (pPrimaryDevExt)
     {
-        VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->pvReqFlush;
+        VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
 
         if (req)
@@ -1864,5 +1981,5 @@
     if (pDevExt->iDevice > 0)
     {
-        DEVICE_EXTENSION *pPrimaryDevExt = (DEVICE_EXTENSION *)pDevExt->pvPrimaryExt;
+        DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
 
         dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
@@ -1870,5 +1987,5 @@
         
         if (   ulEnable
-            && pPrimaryDevExt->ulVbvaEnabled)
+            && pPrimaryDevExt->u.primary.ulVbvaEnabled)
         {
             pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
@@ -1887,5 +2004,5 @@
     {
         /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
-        if (pDevExt->pvReqFlush == NULL)
+        if (pDevExt->u.primary.pvReqFlush == NULL)
         {
             VMMDevVideoAccelFlush *req = NULL;
@@ -1897,5 +2014,5 @@
             if (VBOX_SUCCESS (rc))
             {
-                pDevExt->pvReqFlush = req;
+                pDevExt->u.primary.pvReqFlush = req;
             }
             else
@@ -1983,5 +2100,5 @@
         }
 
-        pDevExt->ulVbvaEnabled = ulEnabled;
+        pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
     }
 
Index: trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideo.h
===================================================================
--- trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideo.h	(revision 3902)
+++ trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideo.h	(revision 4027)
@@ -43,7 +43,7 @@
 #define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
 #define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
-#define VBE_DISPI_INDEX_CMONITORS       0xa
+#define VBE_DISPI_INDEX_VBOX_VIDEO      0xa
 #define VBE_DISPI_ID2                   0xB0C2
-/* The VBOX interface id. Indicates support for VBE_DISPI_INDEX_CMONITORS. */
+/* The VBOX interface id. Indicates support for VBE_DISPI_INDEX_VBOX_VIDEO. */
 #define VBE_DISPI_ID_VBOX_VIDEO         0xBE00
 #define VBE_DISPI_DISABLED              0x00
@@ -55,26 +55,63 @@
 #define VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES      (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB * 1024)
 
-typedef struct
+typedef struct _DEVICE_EXTENSION
 {
-   // Saved information about video modes
-   ULONG CurrentMode;
-
-   /* Pointer to preallocated generic request structure for VMMDevReq_VideoAccelFlush.
-    * Allocated when VBVA status is changed. Deallocated on HwReset.
-    */
-   void *pvReqFlush;
-
-   ULONG iDevice;       /* Device index (0 for primary) */
-   PVOID pvPrimaryExt;  /* Pointer to primary device extension */
-   BOOLEAN bEnabled;    /* Device enabled flag */
-
-   ULONG ulFrameBufferOffset;
-   ULONG ulMaxFrameBufferSize;
-
-   BOOLEAN bDualViewSupported;
+   struct _DEVICE_EXTENSION *pNext;            /* Next extension in the DualView extension list.
+                                                * The primary extension is the first one.
+                                                */
+
+   struct _DEVICE_EXTENSION *pPrimary;         /* Pointer to the primary device extension. */
+
+   ULONG iDevice;                              /* Device index: 0 for primary, otherwise a secondary device. */
+
+
+   ULONG CurrentMode;                          /* Saved information about video modes */
+
+   ULONG ulFrameBufferOffset;                  /* The framebuffer position in the VRAM. */
+   ULONG ulFrameBufferSize;                    /* The size of the current framebuffer. */
+
+   union {
+       /* Information that is only relevant to the primary device or is the same for all devices. */
+       struct {
+           
+           void *pvReqFlush;                   /* Pointer to preallocated generic request structure for
+                                                * VMMDevReq_VideoAccelFlush. Allocated when VBVA status
+                                                * is changed. Deallocated on HwReset.
+                                                */
+
+           
+           ULONG ulVbvaEnabled;                /* Indicates that VBVA mode is enabled. */
+           
+           BOOLEAN bVBoxVideoSupported;        /* TRUE if VBoxVideo extensions, including DualView, are supported by the host. */
+           
+           int cDisplays;                      /* Number of displays. */
+
+           ULONG cbVRAM;                       /* The VRAM size. */
+
+           ULONG cbMiniportHeap;               /* The size of reserved VRAM for miniport driver heap.
+                                                * It is at offset:
+                                                *   cbAdapterMemorySize - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE - cbMiniportHeap
+                                                */
+           PVOID pvMiniportHeap;               /* The pointer to the miniport heap VRAM. 
+                                                * This is mapped by miniport as one block together with adapter info.
+                                                */
+
+           PVOID pvAdapterInformation;         /* The pointer to the last 4K of VRAM. Calculated as 
+                                                *   (uint8_t *)pvMiniportHeap + cbMiniportHeap
+                                                */
+           
+           ULONG ulMaxFrameBufferSize;         /* The size of the VRAM allocated for the a single framebuffer. */
+           
+           ULONG ulDisplayInformationSize;     /* The size of the Display information, which is at offset:
+                                                * ulFrameBufferOffset + ulMaxFrameBufferSize.
+                                                */
+           
+       } primary;
    
-   PVOID AdapterInformation;
-   
-   ULONG ulVbvaEnabled;
+       /* Secondary device information. */
+       struct {
+           BOOLEAN bEnabled;                   /* Device enabled flag */
+       } secondary;
+   } u;
 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
 
