[WIN32SS:GDI] Add a sanity assert
[reactos.git] / win32ss / gdi / eng / pdevobj.c
index 8e5a4d0..a9f959b 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Support for physical devices
- * FILE:             subsystems/win32/win32k/eng/pdevobj.c
+ * FILE:             win32ss/gdi/eng/pdevobj.c
  * PROGRAMER:        Timo Kreuzer (timo.kreuzer@reactos.org)
  */
 
@@ -15,10 +15,10 @@ PPDEVOBJ gppdevPrimary = NULL;
 static PPDEVOBJ gppdevList = NULL;
 static HSEMAPHORE ghsemPDEV;
 
-INIT_FUNCTION
+CODE_SEG("INIT")
 NTSTATUS
 NTAPI
-InitPDEVImpl()
+InitPDEVImpl(VOID)
 {
     ghsemPDEV = EngCreateSemaphore();
     if (!ghsemPDEV) return STATUS_INSUFFICIENT_RESOURCES;
@@ -50,7 +50,7 @@ DbgLookupDHPDEV(DHPDEV dhpdev)
 #endif
 
 PPDEVOBJ
-PDEVOBJ_AllocPDEV()
+PDEVOBJ_AllocPDEV(VOID)
 {
     PPDEVOBJ ppdev;
 
@@ -60,28 +60,51 @@ PDEVOBJ_AllocPDEV()
 
     RtlZeroMemory(ppdev, sizeof(PDEVOBJ));
 
+    ppdev->hsemDevLock = EngCreateSemaphore();
+    if (ppdev->hsemDevLock == NULL)
+    {
+        ExFreePoolWithTag(ppdev, GDITAG_PDEV);
+        return NULL;
+    }
+
+    /* Allocate EDD_DIRECTDRAW_GLOBAL for our ReactX driver */
+    ppdev->pEDDgpl = ExAllocatePoolWithTag(PagedPool, sizeof(EDD_DIRECTDRAW_GLOBAL), GDITAG_PDEV);
+    if (ppdev->pEDDgpl)
+        RtlZeroMemory(ppdev->pEDDgpl, sizeof(EDD_DIRECTDRAW_GLOBAL));
+
     ppdev->cPdevRefs = 1;
 
     return ppdev;
 }
 
+static
+VOID
+PDEVOBJ_vDeletePDEV(
+    PPDEVOBJ ppdev)
+{
+    EngDeleteSemaphore(ppdev->hsemDevLock);
+    if (ppdev->pEDDgpl)
+        ExFreePoolWithTag(ppdev->pEDDgpl, GDITAG_PDEV);
+    ExFreePoolWithTag(ppdev, GDITAG_PDEV);
+}
+
 VOID
 NTAPI
-PDEVOBJ_vRelease(PPDEVOBJ ppdev)
+PDEVOBJ_vRelease(
+    _Inout_ PPDEVOBJ ppdev)
 {
     /* Lock loader */
     EngAcquireSemaphore(ghsemPDEV);
 
     /* Decrease reference count */
-    --ppdev->cPdevRefs;
-
-    ASSERT(ppdev->cPdevRefs >= 0) ;
+    InterlockedDecrement(&ppdev->cPdevRefs);
+    ASSERT(ppdev->cPdevRefs >= 0);
 
     /* Check if references are left */
     if (ppdev->cPdevRefs == 0)
     {
         /* Do we have a surface? */
-        if(ppdev->pSurface)
+        if (ppdev->pSurface)
         {
             /* Release the surface and let the driver free it */
             SURFACE_ShareUnlockSurface(ppdev->pSurface);
@@ -89,29 +112,35 @@ PDEVOBJ_vRelease(PPDEVOBJ ppdev)
         }
 
         /* Do we have a palette? */
-        if(ppdev->ppalSurf)
+        if (ppdev->ppalSurf)
         {
             PALETTE_ShareUnlockPalette(ppdev->ppalSurf);
         }
 
-        /* Disable PDEV */
-        ppdev->pfn.DisablePDEV(ppdev->dhpdev);
+        /* Check if the PDEV was enabled */
+        if (ppdev->dhpdev != NULL)
+        {
+            /* Disable the PDEV */
+            ppdev->pfn.DisablePDEV(ppdev->dhpdev);
+        }
 
         /* Remove it from list */
-        if( ppdev == gppdevList )
-            gppdevList = ppdev->ppdevNext ;
+        if (ppdev == gppdevList)
+        {
+            gppdevList = ppdev->ppdevNext;
+        }
         else
         {
             PPDEVOBJ ppdevCurrent = gppdevList;
-            BOOL found = FALSE ;
+            BOOL found = FALSE;
             while (!found && ppdevCurrent->ppdevNext)
             {
                 if (ppdevCurrent->ppdevNext == ppdev)
                     found = TRUE;
                 else
-                    ppdevCurrent = ppdevCurrent->ppdevNext ;
+                    ppdevCurrent = ppdevCurrent->ppdevNext;
             }
-            if(found)
+            if (found)
                 ppdevCurrent->ppdevNext = ppdev->ppdevNext;
         }
 
@@ -120,12 +149,11 @@ PDEVOBJ_vRelease(PPDEVOBJ ppdev)
             gppdevPrimary = NULL;
 
         /* Free it */
-        ExFreePoolWithTag(ppdev, GDITAG_PDEV );
+        PDEVOBJ_vDeletePDEV(ppdev);
     }
 
     /* Unlock loader */
     EngReleaseSemaphore(ghsemPDEV);
-
 }
 
 BOOL
@@ -155,6 +183,11 @@ PDEVOBJ_bEnablePDEV(
                                   (HDEV)ppdev,
                                   ppdev->pGraphicsDevice->pwszDescription,
                                   ppdev->pGraphicsDevice->DeviceObject);
+    if (ppdev->dhpdev == NULL)
+    {
+        DPRINT1("Failed to enable PDEV\n");
+        return FALSE;
+    }
 
     /* Fix up some values */
     if (ppdev->gdiinfo.ulLogPixelsX == 0)
@@ -203,25 +236,72 @@ PDEVOBJ_pSurface(
 {
     HSURF hsurf;
 
-    /* Check if we already have a surface */
-    if (ppdev->pSurface)
-    {
-        /* Increment reference count */
-        GDIOBJ_vReferenceObjectByPointer(&ppdev->pSurface->BaseObject);
-    }
-    else
+    /* Check if there is no surface for this PDEV yet */
+    if (ppdev->pSurface == NULL)
     {
         /* Call the drivers DrvEnableSurface */
         hsurf = ppdev->pldev->pfn.EnableSurface(ppdev->dhpdev);
+        if (hsurf== NULL)
+        {
+            DPRINT1("Failed to create PDEV surface!\n");
+            return NULL;
+        }
 
-        /* Lock the surface */
+        /* Get a reference to the surface */
         ppdev->pSurface = SURFACE_ShareLockSurface(hsurf);
+        NT_ASSERT(ppdev->pSurface != NULL);
     }
 
+    /* Increment reference count */
+    GDIOBJ_vReferenceObjectByPointer(&ppdev->pSurface->BaseObject);
+
     DPRINT("PDEVOBJ_pSurface() returning %p\n", ppdev->pSurface);
     return ppdev->pSurface;
 }
 
+VOID
+NTAPI
+PDEVOBJ_vRefreshModeList(
+    PPDEVOBJ ppdev)
+{
+    PGRAPHICS_DEVICE pGraphicsDevice;
+    PDEVMODEINFO pdminfo, pdmiNext;
+    DEVMODEW dmDefault;
+    DEVMODEW dmCurrent;
+
+    /* Lock the PDEV */
+    EngAcquireSemaphore(ppdev->hsemDevLock);
+
+    pGraphicsDevice = ppdev->pGraphicsDevice;
+
+    /* Remember our default mode */
+    dmDefault = *pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm;
+    dmCurrent = *ppdev->pdmwDev;
+
+    /* Clear out the modes */
+    for (pdminfo = pGraphicsDevice->pdevmodeInfo;
+         pdminfo;
+         pdminfo = pdmiNext)
+    {
+        pdmiNext = pdminfo->pdmiNext;
+        ExFreePoolWithTag(pdminfo, GDITAG_DEVMODE);
+    }
+    pGraphicsDevice->pdevmodeInfo = NULL;
+    ExFreePoolWithTag(pGraphicsDevice->pDevModeList, GDITAG_GDEVICE);
+    pGraphicsDevice->pDevModeList = NULL;
+
+    /* Now re-populate the list */
+    if (!EngpPopulateDeviceModeList(pGraphicsDevice, &dmDefault))
+    {
+        DPRINT1("FIXME: EngpPopulateDeviceModeList failed, we just destroyed a perfectly good mode list\n");
+    }
+
+    ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, &dmCurrent);
+
+    /* Unlock PDEV */
+    EngReleaseSemaphore(ppdev->hsemDevLock);
+}
+
 PDEVMODEW
 NTAPI
 PDEVOBJ_pdmMatchDevMode(
@@ -241,7 +321,7 @@ PDEVOBJ_pdmMatchDevMode(
 
         /* Compare asked DEVMODE fields
          * Only compare those that are valid in both DEVMODE structs */
-        dwFields = pdmCurrent->dmFields & pdm->dmFields ;
+        dwFields = pdmCurrent->dmFields & pdm->dmFields;
 
         /* For now, we only need those */
         if ((dwFields & DM_BITSPERPEL) &&
@@ -269,6 +349,7 @@ EngpCreatePDEV(
 {
     PGRAPHICS_DEVICE pGraphicsDevice;
     PPDEVOBJ ppdev;
+
     DPRINT("EngpCreatePDEV(%wZ, %p)\n", pustrDeviceName, pdm);
 
     /* Try to find the GRAPHICS_DEVICE */
@@ -284,6 +365,7 @@ EngpCreatePDEV(
     }
     else
     {
+        ASSERT(gpPrimaryGraphicsDevice);
         pGraphicsDevice = gpPrimaryGraphicsDevice;
     }
 
@@ -310,7 +392,7 @@ EngpCreatePDEV(
         DPRINT1("Could not load display driver '%ls', '%ls'\n",
                 pGraphicsDevice->pDiplayDrivers,
                 pdm->dmDeviceName);
-        ExFreePoolWithTag(ppdev, GDITAG_PDEV);
+        PDEVOBJ_vRelease(ppdev);
         return NULL;
     }
 
@@ -323,9 +405,12 @@ EngpCreatePDEV(
         ppdev->pfnMovePointer = EngMovePointer;
 
     ppdev->pGraphicsDevice = pGraphicsDevice;
-    ppdev->hsemDevLock = EngCreateSemaphore();
+
+    // DxEngGetHdevData asks for Graphics DeviceObject in hSpooler field
+    ppdev->hSpooler = ppdev->pGraphicsDevice->DeviceObject;
+
     // Should we change the ative mode of pGraphicsDevice ?
-    ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, pdm) ;
+    ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
 
     /* FIXME! */
     ppdev->flFlags = PDEV_DISPLAY;
@@ -337,7 +422,8 @@ EngpCreatePDEV(
     if (!PDEVOBJ_bEnablePDEV(ppdev, pdm, NULL))
     {
         DPRINT1("Failed to enable PDEV!\n");
-        ASSERT(FALSE);
+        PDEVOBJ_vRelease(ppdev);
+        return NULL;
     }
 
     /* FIXME: this must be done in a better way */
@@ -350,8 +436,8 @@ EngpCreatePDEV(
     return ppdev;
 }
 
-VOID
 FORCEINLINE
+VOID
 SwitchPointer(
     _Inout_ PVOID pvPointer1,
     _Inout_ PVOID pvPointer2)
@@ -441,10 +527,10 @@ PDEVOBJ_bSwitchMode(
     // Lookup the GraphicsDevice + select DEVMODE
     // pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
 
-    /* 1. Temporarily disable the current PDEV */
+    /* 1. Temporarily disable the current PDEV and reset video to its default mode */
     if (!ppdev->pfn.AssertMode(ppdev->dhpdev, FALSE))
     {
-        DPRINT1("DrvAssertMode failed\n");
+        DPRINT1("DrvAssertMode(FALSE) failed\n");
         goto leave;
     }
 
@@ -454,15 +540,16 @@ PDEVOBJ_bSwitchMode(
     if (!ppdevTmp)
     {
         DPRINT1("Failed to create a new PDEV\n");
-        goto leave;
+        goto leave2;
     }
 
     /* 3. Create a new surface */
     pSurface = PDEVOBJ_pSurface(ppdevTmp);
     if (!pSurface)
     {
-        DPRINT1("DrvEnableSurface failed\n");
-        goto leave;
+        DPRINT1("PDEVOBJ_pSurface failed\n");
+        PDEVOBJ_vRelease(ppdevTmp);
+        goto leave2;
     }
 
     /* 4. Get DirectDraw information */
@@ -477,17 +564,26 @@ PDEVOBJ_bSwitchMode(
     PDEVOBJ_vRelease(ppdevTmp);
 
     /* Update primary display capabilities */
-    if(ppdev == gppdevPrimary)
+    if (ppdev == gppdevPrimary)
     {
         PDEVOBJ_vGetDeviceCaps(ppdev, &GdiHandleTable->DevCaps);
     }
 
     /* Success! */
     retval = TRUE;
+
+leave2:
+    /* Set the new video mode, or restore the original one in case of failure */
+    if (!ppdev->pfn.AssertMode(ppdev->dhpdev, TRUE))
+    {
+        DPRINT1("DrvAssertMode(TRUE) failed\n");
+    }
+
 leave:
-    /* Unlock PDEV */
-    EngReleaseSemaphore(ppdev->hsemDevLock);
+    /* Unlock everything else */
     EngReleaseSemaphore(ghsemPDEV);
+    /* Unlock the PDEV */
+    EngReleaseSemaphore(ppdev->hsemDevLock);
 
     DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface);
 
@@ -535,7 +631,7 @@ EngpGetPDEV(
     if (ppdev)
     {
         /* Yes, reference the PDEV */
-        InterlockedIncrement(&ppdev->cPdevRefs);
+        PDEVOBJ_vReference(ppdev);
     }
     else
     {