[WIN32SS] Implement PDEVOBJ_lChangeDisplaySettings to create initial MDEV

This function can create a MDEV for the whole display (maybe containing multiple
PDEVs), or update settings of a specific PDEV.

- call PDEVOBJ_lChangeDisplaySettings when switching to graphics mode.
- modify EngpGetPDEV to search requested PDEV only in current MDEV
This commit is contained in:
Hervé Poussineau 2022-03-20 17:38:16 +01:00 committed by hpoussin
parent 9db63ad595
commit 2d2824f1b9
3 changed files with 185 additions and 27 deletions

View file

@ -643,8 +643,9 @@ EngpGetPDEV(
_In_opt_ PUNICODE_STRING pustrDeviceName)
{
UNICODE_STRING ustrCurrent;
PPDEVOBJ ppdev;
PPDEVOBJ ppdev = NULL;
PGRAPHICS_DEVICE pGraphicsDevice;
ULONG i;
/* Acquire PDEV lock */
EngAcquireSemaphore(ghsemPDEV);
@ -653,16 +654,17 @@ EngpGetPDEV(
if (pustrDeviceName)
{
/* Loop all present PDEVs */
for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext)
for (i = 0; i < gpmdev->cDev; i++)
{
/* Get a pointer to the GRAPHICS_DEVICE */
pGraphicsDevice = ppdev->pGraphicsDevice;
pGraphicsDevice = gpmdev->dev[i].ppdev->pGraphicsDevice;
/* Compare the name */
RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName);
if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE))
{
/* Found! */
ppdev = gpmdev->dev[i].ppdev;
break;
}
}
@ -679,27 +681,6 @@ EngpGetPDEV(
/* Yes, reference the PDEV */
PDEVOBJ_vReference(ppdev);
}
else
{
if (pustrDeviceName)
pGraphicsDevice = EngpFindGraphicsDevice(pustrDeviceName, 0);
if (!pGraphicsDevice)
pGraphicsDevice = gpPrimaryGraphicsDevice;
/* No, create a new PDEV for the given device */
ppdev = PDEVOBJ_Create(pGraphicsDevice,
pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm,
LDEV_DEVICE_DISPLAY);
if (ppdev)
{
/* Set as primary PDEV, if we don't have one yet */
if (!gpmdev->ppdevGlobal)
{
gpmdev->ppdevGlobal = ppdev;
ppdev->pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
}
}
}
/* Release PDEV lock */
EngReleaseSemaphore(ghsemPDEV);
@ -707,6 +688,168 @@ EngpGetPDEV(
return ppdev;
}
LONG
PDEVOBJ_lChangeDisplaySettings(
_In_opt_ PUNICODE_STRING pustrDeviceName,
_In_opt_ PDEVMODEW RequestedMode,
_In_opt_ PMDEVOBJ pmdevOld,
_Out_ PMDEVOBJ *ppmdevNew,
_In_ BOOL bSearchClosestMode)
{
PGRAPHICS_DEVICE pGraphicsDevice;
PMDEVOBJ pmdev = NULL;
PDEVMODEW pdm = NULL;
ULONG lRet = DISP_CHANGE_SUCCESSFUL;
ULONG i, j;
TRACE("PDEVOBJ_lChangeDisplaySettings('%wZ' '%dx%dx%d (%d Hz)' %p %p)\n",
pustrDeviceName,
RequestedMode ? RequestedMode->dmPelsWidth : 0,
RequestedMode ? RequestedMode->dmPelsHeight : 0,
RequestedMode ? RequestedMode->dmBitsPerPel : 0,
RequestedMode ? RequestedMode->dmDisplayFrequency : 0,
pmdevOld, ppmdevNew);
if (pustrDeviceName)
{
pGraphicsDevice = EngpFindGraphicsDevice(pustrDeviceName, 0);
if (!pGraphicsDevice)
{
ERR("Wrong device name provided: '%wZ'\n", pustrDeviceName);
lRet = DISP_CHANGE_BADPARAM;
goto cleanup;
}
}
else if (RequestedMode)
{
pGraphicsDevice = gpPrimaryGraphicsDevice;
if (!pGraphicsDevice)
{
ERR("Wrong device'\n");
lRet = DISP_CHANGE_BADPARAM;
goto cleanup;
}
}
if (pGraphicsDevice)
{
if (!LDEVOBJ_bProbeAndCaptureDevmode(pGraphicsDevice, RequestedMode, &pdm, bSearchClosestMode))
{
ERR("DrvProbeAndCaptureDevmode() failed\n");
lRet = DISP_CHANGE_BADMODE;
goto cleanup;
}
}
/* Here, we know that input parameters were correct */
{
/* Create new MDEV. Note that if we provide a device name,
* MDEV will only contain one device.
* */
if (pmdevOld)
{
/* Disable old MDEV */
if (MDEVOBJ_bDisable(pmdevOld))
{
/* Create new MDEV. On failure, reenable old MDEV */
pmdev = MDEVOBJ_Create(pustrDeviceName, pdm);
if (!pmdev)
MDEVOBJ_vEnable(pmdevOld);
}
}
else
{
pmdev = MDEVOBJ_Create(pustrDeviceName, pdm);
}
if (!pmdev)
{
ERR("Failed to create new MDEV\n");
lRet = DISP_CHANGE_FAILED;
goto cleanup;
}
lRet = DISP_CHANGE_SUCCESSFUL;
*ppmdevNew = pmdev;
/* We now have to do the mode switch */
if (pustrDeviceName && pmdevOld)
{
/* We changed settings of one device. Add other devices which were already present */
for (i = 0; i < pmdevOld->cDev; i++)
{
for (j = 0; j < pmdev->cDev; j++)
{
if (pmdev->dev[j].ppdev->pGraphicsDevice == pmdevOld->dev[i].ppdev->pGraphicsDevice)
{
if (PDEVOBJ_bDynamicModeChange(pmdevOld->dev[i].ppdev, pmdev->dev[j].ppdev))
{
PPDEVOBJ tmp = pmdevOld->dev[i].ppdev;
pmdevOld->dev[i].ppdev = pmdev->dev[j].ppdev;
pmdev->dev[j].ppdev = tmp;
}
else
{
ERR("Failed to apply new settings\n");
UNIMPLEMENTED;
ASSERT(FALSE);
}
break;
}
}
if (j == pmdev->cDev)
{
PDEVOBJ_vReference(pmdevOld->dev[i].ppdev);
pmdev->dev[pmdev->cDev].ppdev = pmdevOld->dev[i].ppdev;
pmdev->cDev++;
}
}
}
if (pmdev->cDev == 1)
{
pmdev->ppdevGlobal = pmdev->dev[0].ppdev;
}
else
{
/* FIXME: currently, only use the first display */
UNIMPLEMENTED;
PDEVOBJ_vReference(pmdev->dev[0].ppdev);
pmdev->ppdevGlobal = pmdev->dev[0].ppdev;
}
if (pmdevOld)
{
/* Search PDEVs which were in pmdevOld, but are not anymore in pmdev, and disable them */
for (i = 0; i < pmdevOld->cDev; i++)
{
for (j = 0; j < pmdev->cDev; j++)
{
if (pmdev->dev[j].ppdev->pGraphicsDevice == pmdevOld->dev[i].ppdev->pGraphicsDevice)
break;
}
if (j == pmdev->cDev)
PDEVOBJ_bDisableDisplay(pmdevOld->dev[i].ppdev);
}
}
}
cleanup:
if (lRet != DISP_CHANGE_SUCCESSFUL)
{
*ppmdevNew = NULL;
if (pmdev)
MDEVOBJ_vDestroy(pmdev);
if (pdm && pdm != RequestedMode)
ExFreePoolWithTag(pdm, GDITAG_DEVMODE);
}
return lRet;
}
INT
NTAPI
PDEVOBJ_iGetColorManagementCaps(PPDEVOBJ ppdev)

View file

@ -228,4 +228,20 @@ PDEVOBJ_Create(
_In_opt_ PDEVMODEW pdm,
_In_ ULONG ldevtype);
/* Change display settings:
* - pustrDeviceName: name of the device to change settings. Can be NULL to specify whole display surface
* - RequestedMode: new parameters for device. Ignored if pstrDeviceName is NULL
* - pmdevOld: old MDEVOBJ. Can be NULL if we are creating the first one
* - ppdevNew: MDEVOBJ created by this function, with the new settings
* - bSearchClosestMode: do we need to search exact requested mode, or a mostly similar one
* Return value: a DISP_CHANGE_* value
*/
LONG
PDEVOBJ_lChangeDisplaySettings(
_In_opt_ PUNICODE_STRING pustrDeviceName,
_In_opt_ PDEVMODEW RequestedMode,
_In_opt_ PMDEVOBJ pmdevOld,
_Out_ PMDEVOBJ *ppmdevNew,
_In_ BOOL bSearchClosestMode);
#endif /* !__WIN32K_PDEVOBJ_H */

View file

@ -263,10 +263,9 @@ co_IntInitializeDesktopGraphics(VOID)
UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
PDESKTOP pdesk;
gpmdev = ExAllocatePoolZero(PagedPool, sizeof(MDEVOBJ), GDITAG_MDEV);
if (!gpmdev)
if (PDEVOBJ_lChangeDisplaySettings(NULL, NULL, NULL, &gpmdev, TRUE) != DISP_CHANGE_SUCCESSFUL)
{
ERR("Failed to allocate MDEV.\n");
ERR("PDEVOBJ_lChangeDisplaySettings() failed.\n");
return FALSE;
}