mirror of
https://github.com/VirtualDrivers/Virtual-Display-Driver.git
synced 2026-10-21 22:22:27 -05:00
1084 lines
53 KiB
C++
1084 lines
53 KiB
C++
/******************************Module*Header*******************************\
|
|
* Module Name: bdd_dmm.hxx
|
|
*
|
|
* Basic Display Driver display-mode management (DMM) function implementations
|
|
*
|
|
*
|
|
* Copyright (c) 2010 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "BDD.hxx"
|
|
|
|
#pragma code_seg("PAGE")
|
|
|
|
// Display-Only Devices can only return display modes of D3DDDIFMT_A8R8G8B8.
|
|
// Color conversion takes place if the app's fullscreen backbuffer has different format.
|
|
// Full display drivers can add more if the hardware supports them.
|
|
D3DDDIFORMAT gBddPixelFormats[] = {
|
|
D3DDDIFMT_A8R8G8B8
|
|
};
|
|
|
|
// TODO: Need to also check pinned modes and the path parameters, not just topology
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
BDD_ASSERT(pIsSupportedVidPn != NULL);
|
|
|
|
if (pIsSupportedVidPn->hDesiredVidPn == 0)
|
|
{
|
|
// A null desired VidPn is supported
|
|
pIsSupportedVidPn->IsVidPnSupported = TRUE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// Default to not supported, until shown it is supported
|
|
pIsSupportedVidPn->IsVidPnSupported = FALSE;
|
|
|
|
CONST DXGK_VIDPN_INTERFACE* pVidPnInterface;
|
|
NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pIsSupportedVidPn->hDesiredVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn);
|
|
return Status;
|
|
}
|
|
|
|
D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology;
|
|
CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface;
|
|
Status = pVidPnInterface->pfnGetTopology(pIsSupportedVidPn->hDesiredVidPn, &hVidPnTopology, &pVidPnTopologyInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn);
|
|
return Status;
|
|
}
|
|
|
|
// For every source in this topology, make sure they don't have more paths than there are targets
|
|
for (D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = 0; SourceId < MAX_VIEWS; ++SourceId)
|
|
{
|
|
SIZE_T NumPathsFromSource = 0;
|
|
Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, SourceId, &NumPathsFromSource);
|
|
if (Status == STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY)
|
|
{
|
|
continue;
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnGetNumPathsFromSource failed with Status = 0x%I64x. hVidPnTopology = 0x%I64x, SourceId = 0x%I64x",
|
|
Status, hVidPnTopology, SourceId);
|
|
return Status;
|
|
}
|
|
else if (NumPathsFromSource > MAX_CHILDREN)
|
|
{
|
|
// This VidPn is not supported, which has already been set as the default
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
// All sources succeeded so this VidPn is supported
|
|
pIsSupportedVidPn->IsVidPnSupported = TRUE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
BDD_ASSERT(pRecommendFunctionalVidPn == NULL);
|
|
|
|
return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN;
|
|
}
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
BDD_ASSERT(pRecommendVidPnTopology == NULL);
|
|
|
|
return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN;
|
|
}
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
// This is always called to recommend modes for the monitor. The sample driver doesn't provide EDID for a monitor, so
|
|
// the OS prefills the list with default monitor modes. Since the required mode might not be in the list, it should
|
|
// be provided as a recommended mode.
|
|
return AddSingleMonitorMode(pRecommendMonitorModes);
|
|
}
|
|
|
|
// Tell DMM about all the modes, etc. that are supported
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
BDD_ASSERT(pEnumCofuncModality != NULL);
|
|
|
|
D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0;
|
|
D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0;
|
|
D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet = 0;
|
|
CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
|
|
CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL;
|
|
CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL;
|
|
CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface = NULL;
|
|
CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL;
|
|
CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPathTemp = NULL; // Used for AcquireNextPathInfo
|
|
CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo = NULL;
|
|
CONST D3DKMDT_VIDPN_TARGET_MODE* pVidPnPinnedTargetModeInfo = NULL;
|
|
|
|
// Get the VidPn Interface so we can get the 'Source Mode Set', 'Target Mode Set' and 'VidPn Topology' interfaces
|
|
NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pEnumCofuncModality->hConstrainingVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn);
|
|
return Status;
|
|
}
|
|
|
|
// Get the VidPn Topology interface so we can enumerate all paths
|
|
Status = pVidPnInterface->pfnGetTopology(pEnumCofuncModality->hConstrainingVidPn, &hVidPnTopology, &pVidPnTopologyInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn);
|
|
return Status;
|
|
}
|
|
|
|
// Get the first path before we start looping through them
|
|
Status = pVidPnTopologyInterface->pfnAcquireFirstPathInfo(hVidPnTopology, &pVidPnPresentPath);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnAcquireFirstPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);
|
|
return Status;
|
|
}
|
|
|
|
// Loop through all available paths.
|
|
while (Status != STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET)
|
|
{
|
|
// Get the Source Mode Set interface so the pinned mode can be retrieved
|
|
Status = pVidPnInterface->pfnAcquireSourceModeSet(pEnumCofuncModality->hConstrainingVidPn,
|
|
pVidPnPresentPath->VidPnSourceId,
|
|
&hVidPnSourceModeSet,
|
|
&pVidPnSourceModeSetInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId);
|
|
break;
|
|
}
|
|
|
|
// Get the pinned mode, needed when VidPnSource isn't pivot, and when VidPnTarget isn't pivot
|
|
Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pVidPnPinnedSourceModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet);
|
|
break;
|
|
}
|
|
|
|
// SOURCE MODES: If this source mode isn't the pivot point, do work on the source mode set
|
|
if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNSOURCE) &&
|
|
(pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId)))
|
|
{
|
|
// If there's no pinned source add possible modes (otherwise they've already been added)
|
|
if (pVidPnPinnedSourceModeInfo == NULL)
|
|
{
|
|
// Release the acquired source mode set, since going to create a new one to put all modes in
|
|
Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
|
|
break;
|
|
}
|
|
hVidPnSourceModeSet = 0; // Successfully released it
|
|
|
|
// Create a new source mode set which will be added to the constraining VidPn with all the possible modes
|
|
Status = pVidPnInterface->pfnCreateNewSourceModeSet(pEnumCofuncModality->hConstrainingVidPn,
|
|
pVidPnPresentPath->VidPnSourceId,
|
|
&hVidPnSourceModeSet,
|
|
&pVidPnSourceModeSetInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnCreateNewSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId);
|
|
break;
|
|
}
|
|
|
|
// Add the appropriate modes to the source mode set
|
|
{
|
|
Status = AddSingleSourceMode(pVidPnSourceModeSetInterface, hVidPnSourceModeSet, pVidPnPresentPath->VidPnSourceId);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Give DMM back the source modes just populated
|
|
Status = pVidPnInterface->pfnAssignSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR4("pfnAssignSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet);
|
|
break;
|
|
}
|
|
hVidPnSourceModeSet = 0; // Successfully assigned it (equivalent to releasing it)
|
|
}
|
|
}// End: SOURCE MODES
|
|
|
|
// TARGET MODES: If this target mode isn't the pivot point, do work on the target mode set
|
|
if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNTARGET) &&
|
|
(pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))
|
|
{
|
|
// Get the Target Mode Set interface so modes can be added if necessary
|
|
Status = pVidPnInterface->pfnAcquireTargetModeSet(pEnumCofuncModality->hConstrainingVidPn,
|
|
pVidPnPresentPath->VidPnTargetId,
|
|
&hVidPnTargetModeSet,
|
|
&pVidPnTargetModeSetInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnAcquireTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId);
|
|
break;
|
|
}
|
|
|
|
Status = pVidPnTargetModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnTargetModeSet, &pVidPnPinnedTargetModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet);
|
|
break;
|
|
}
|
|
|
|
// If there's no pinned target add possible modes (otherwise they've already been added)
|
|
if (pVidPnPinnedTargetModeInfo == NULL)
|
|
{
|
|
// Release the acquired target mode set, since going to create a new one to put all modes in
|
|
Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
|
|
break;
|
|
}
|
|
hVidPnTargetModeSet = 0; // Successfully released it
|
|
|
|
// Create a new target mode set which will be added to the constraining VidPn with all the possible modes
|
|
Status = pVidPnInterface->pfnCreateNewTargetModeSet(pEnumCofuncModality->hConstrainingVidPn,
|
|
pVidPnPresentPath->VidPnTargetId,
|
|
&hVidPnTargetModeSet,
|
|
&pVidPnTargetModeSetInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnCreateNewTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId);
|
|
break;
|
|
}
|
|
|
|
Status = AddSingleTargetMode(pVidPnTargetModeSetInterface, hVidPnTargetModeSet, pVidPnPinnedSourceModeInfo, pVidPnPresentPath->VidPnSourceId);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Give DMM back the source modes just populated
|
|
Status = pVidPnInterface->pfnAssignTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR4("pfnAssignTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet);
|
|
break;
|
|
}
|
|
hVidPnTargetModeSet = 0; // Successfully assigned it (equivalent to releasing it)
|
|
}
|
|
else
|
|
{
|
|
// Release the pinned target as there's no other work to do
|
|
Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnPinnedTargetModeInfo = 0x%I64x",
|
|
Status, hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);
|
|
break;
|
|
}
|
|
pVidPnPinnedTargetModeInfo = NULL; // Successfully released it
|
|
|
|
// Release the acquired target mode set, since it is no longer needed
|
|
Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
|
|
break;
|
|
}
|
|
hVidPnTargetModeSet = 0; // Successfully released it
|
|
}
|
|
}// End: TARGET MODES
|
|
|
|
// Nothing else needs the pinned source mode so release it
|
|
if (pVidPnPinnedSourceModeInfo != NULL)
|
|
{
|
|
Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnPinnedSourceModeInfo = 0x%I64x",
|
|
Status, hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);
|
|
break;
|
|
}
|
|
pVidPnPinnedSourceModeInfo = NULL; // Successfully released it
|
|
}
|
|
|
|
// With the pinned source mode now released, if the source mode set hasn't been released, release that as well
|
|
if (hVidPnSourceModeSet != 0)
|
|
{
|
|
Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",
|
|
Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
|
|
break;
|
|
}
|
|
hVidPnSourceModeSet = 0; // Successfully released it
|
|
}
|
|
|
|
// If modifying support fields, need to modify a local version of a path structure since the retrieved one is const
|
|
D3DKMDT_VIDPN_PRESENT_PATH LocalVidPnPresentPath = *pVidPnPresentPath;
|
|
BOOLEAN SupportFieldsModified = FALSE;
|
|
|
|
// SCALING: If this path's scaling isn't the pivot point, do work on the scaling support
|
|
if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_SCALING) &&
|
|
(pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) &&
|
|
(pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))
|
|
{
|
|
// If the scaling is unpinned, then modify the scaling support field
|
|
if (pVidPnPresentPath->ContentTransformation.Scaling == D3DKMDT_VPPS_UNPINNED)
|
|
{
|
|
// Identity and centered scaling are supported, but not any stretch modes
|
|
RtlZeroMemory(&(LocalVidPnPresentPath.ContentTransformation.ScalingSupport), sizeof(D3DKMDT_VIDPN_PRESENT_PATH_SCALING_SUPPORT));
|
|
LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Identity = 1;
|
|
LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Centered = 1;
|
|
SupportFieldsModified = TRUE;
|
|
}
|
|
} // End: SCALING
|
|
|
|
// ROTATION: If this path's rotation isn't the pivot point, do work on the rotation support
|
|
if (!((pEnumCofuncModality->EnumPivotType != D3DKMDT_EPT_ROTATION) &&
|
|
(pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) &&
|
|
(pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))
|
|
{
|
|
// If the rotation is unpinned, then modify the rotation support field
|
|
if (pVidPnPresentPath->ContentTransformation.Rotation == D3DKMDT_VPPR_UNPINNED)
|
|
{
|
|
LocalVidPnPresentPath.ContentTransformation.RotationSupport.Identity = 1;
|
|
// Sample supports only Rotate90
|
|
LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate90 = 1;
|
|
LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate180 = 0;
|
|
LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate270 = 0;
|
|
|
|
// Since clone is not supported, should not support path-independent rotations
|
|
LocalVidPnPresentPath.ContentTransformation.RotationSupport.Offset0 = 1;
|
|
|
|
SupportFieldsModified = TRUE;
|
|
}
|
|
} // End: ROTATION
|
|
|
|
if (SupportFieldsModified)
|
|
{
|
|
// The correct path will be found by this function and the appropriate fields updated
|
|
Status = pVidPnTopologyInterface->pfnUpdatePathSupportInfo(hVidPnTopology, &LocalVidPnPresentPath);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnUpdatePathSupportInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Get the next path...
|
|
// (NOTE: This is the value of Status that will return STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET when it's time to quit the loop)
|
|
pVidPnPresentPathTemp = pVidPnPresentPath;
|
|
Status = pVidPnTopologyInterface->pfnAcquireNextPathInfo(hVidPnTopology, pVidPnPresentPathTemp, &pVidPnPresentPath);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnAcquireNextPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", Status, hVidPnTopology, pVidPnPresentPathTemp);
|
|
break;
|
|
}
|
|
|
|
// ...and release the last path
|
|
NTSTATUS TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp);
|
|
if (!NT_SUCCESS(TempStatus))
|
|
{
|
|
BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", TempStatus, hVidPnTopology, pVidPnPresentPathTemp);
|
|
Status = TempStatus;
|
|
break;
|
|
}
|
|
pVidPnPresentPathTemp = NULL; // Successfully released it
|
|
}// End: while loop for paths in topology
|
|
|
|
// If quit the while loop normally, set the return value to success
|
|
if (Status == STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET)
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
// Release any resources hanging around because the loop was quit early.
|
|
// Since in normal execution everything should be released by this point, TempStatus is initialized to a bogus error to be used as an
|
|
// assertion that if anything had to be released now (TempStatus changing) Status isn't successful.
|
|
NTSTATUS TempStatus = STATUS_NOT_FOUND;
|
|
|
|
if ((pVidPnSourceModeSetInterface != NULL) &&
|
|
(pVidPnPinnedSourceModeInfo != NULL))
|
|
{
|
|
TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);
|
|
BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
|
|
}
|
|
|
|
if ((pVidPnTargetModeSetInterface != NULL) &&
|
|
(pVidPnPinnedTargetModeInfo != NULL))
|
|
{
|
|
TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);
|
|
BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
|
|
}
|
|
|
|
if (pVidPnPresentPath != NULL)
|
|
{
|
|
TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);
|
|
BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
|
|
}
|
|
|
|
if (pVidPnPresentPathTemp != NULL)
|
|
{
|
|
TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp);
|
|
BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
|
|
}
|
|
|
|
if (hVidPnSourceModeSet != 0)
|
|
{
|
|
TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
|
|
BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
|
|
}
|
|
|
|
if (hVidPnTargetModeSet != 0)
|
|
{
|
|
TempStatus = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
|
|
BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
|
|
}
|
|
|
|
BDD_ASSERT_CHK(TempStatus == STATUS_NOT_FOUND || Status != STATUS_SUCCESS);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
BDD_ASSERT(pSetVidPnSourceVisibility != NULL);
|
|
BDD_ASSERT((pSetVidPnSourceVisibility->VidPnSourceId < MAX_VIEWS) ||
|
|
(pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL));
|
|
|
|
UINT StartVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? 0 : pSetVidPnSourceVisibility->VidPnSourceId;
|
|
UINT MaxVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? MAX_VIEWS : pSetVidPnSourceVisibility->VidPnSourceId + 1;
|
|
|
|
for (UINT SourceId = StartVidPnSourceId; SourceId < MaxVidPnSourceId; ++SourceId)
|
|
{
|
|
if (pSetVidPnSourceVisibility->Visible)
|
|
{
|
|
m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
BlackOutScreen(SourceId);
|
|
}
|
|
|
|
// Store current visibility so it can be dealt with during Present call
|
|
m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// NOTE: The value of pCommitVidPn->MonitorConnectivityChecks is ignored, since BDD is unable to recognize whether a monitor is connected or not
|
|
// The value of pCommitVidPn->hPrimaryAllocation is also ignored, since BDD is a display only driver and does not deal with allocations
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
BDD_ASSERT(pCommitVidPn != NULL);
|
|
BDD_ASSERT(pCommitVidPn->AffectedVidPnSourceId < MAX_VIEWS);
|
|
|
|
NTSTATUS Status;
|
|
SIZE_T NumPaths = 0;
|
|
D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0;
|
|
D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0;
|
|
CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
|
|
CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL;
|
|
CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL;
|
|
CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL;
|
|
CONST D3DKMDT_VIDPN_SOURCE_MODE* pPinnedVidPnSourceModeInfo = NULL;
|
|
|
|
// Check this CommitVidPn is for the mode change notification when monitor is in power off state.
|
|
if (pCommitVidPn->Flags.PathPoweredOff)
|
|
{
|
|
// Ignore the commitVidPn call for the mode change notification when monitor is in power off state.
|
|
Status = STATUS_SUCCESS;
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
// Get the VidPn Interface so we can get the 'Source Mode Set' and 'VidPn Topology' interfaces
|
|
Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPn->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn);
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
// Get the VidPn Topology interface so can enumerate paths from source
|
|
Status = pVidPnInterface->pfnGetTopology(pCommitVidPn->hFunctionalVidPn, &hVidPnTopology, &pVidPnTopologyInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn);
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
// Find out the number of paths now, if it's 0 don't bother with source mode set and pinned mode, just clear current and then quit
|
|
Status = pVidPnTopologyInterface->pfnGetNumPaths(hVidPnTopology, &NumPaths);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnGetNumPaths failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
if (NumPaths != 0)
|
|
{
|
|
// Get the Source Mode Set interface so we can get the pinned mode
|
|
Status = pVidPnInterface->pfnAcquireSourceModeSet(pCommitVidPn->hFunctionalVidPn,
|
|
pCommitVidPn->AffectedVidPnSourceId,
|
|
&hVidPnSourceModeSet,
|
|
&pVidPnSourceModeSetInterface);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x, SourceId = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn, pCommitVidPn->AffectedVidPnSourceId);
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
// Get the mode that is being pinned
|
|
Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pPinnedVidPnSourceModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn);
|
|
goto CommitVidPnExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This will cause the successful quit below
|
|
pPinnedVidPnSourceModeInfo = NULL;
|
|
}
|
|
|
|
if (m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr &&
|
|
!m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.DoNotMapOrUnmap)
|
|
{
|
|
Status = UnmapFrameBuffer(m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr,
|
|
m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Pitch * m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Height);
|
|
m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr = NULL;
|
|
m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.FrameBufferIsActive = FALSE;
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto CommitVidPnExit;
|
|
}
|
|
}
|
|
|
|
if (pPinnedVidPnSourceModeInfo == NULL)
|
|
{
|
|
// There is no mode to pin on this source, any old paths here have already been cleared
|
|
Status = STATUS_SUCCESS;
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
Status = IsVidPnSourceModeFieldsValid(pPinnedVidPnSourceModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
// Get the number of paths from this source so we can loop through all paths
|
|
SIZE_T NumPathsFromSource = 0;
|
|
Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, &NumPathsFromSource);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR2("pfnGetNumPathsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
// Loop through all paths to set this mode
|
|
for (SIZE_T PathIndex = 0; PathIndex < NumPathsFromSource; ++PathIndex)
|
|
{
|
|
// Get the target id for this path
|
|
D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId = D3DDDI_ID_UNINITIALIZED;
|
|
Status = pVidPnTopologyInterface->pfnEnumPathTargetsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex, &TargetId);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR4("pfnEnumPathTargetsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, PathIndex = 0x%I64x",
|
|
Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex);
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
// Get the actual path info
|
|
Status = pVidPnTopologyInterface->pfnAcquirePathInfo(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId, &pVidPnPresentPath);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR4("pfnAcquirePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, TargetId = 0x%I64x",
|
|
Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId);
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
Status = IsVidPnPathFieldsValid(pVidPnPresentPath);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
Status = SetSourceModeAndPath(pPinnedVidPnSourceModeInfo, pVidPnPresentPath);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto CommitVidPnExit;
|
|
}
|
|
|
|
Status = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopoogy = 0x%I64x, pVidPnPresentPath = 0x%I64x",
|
|
Status, hVidPnTopology, pVidPnPresentPath);
|
|
goto CommitVidPnExit;
|
|
}
|
|
pVidPnPresentPath = NULL; // Successfully released it
|
|
}
|
|
|
|
CommitVidPnExit:
|
|
|
|
NTSTATUS TempStatus;
|
|
|
|
if ((pVidPnSourceModeSetInterface != NULL) &&
|
|
(hVidPnSourceModeSet != 0) &&
|
|
(pPinnedVidPnSourceModeInfo != NULL))
|
|
{
|
|
TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pPinnedVidPnSourceModeInfo);
|
|
NT_ASSERT(NT_SUCCESS(TempStatus));
|
|
}
|
|
|
|
if ((pVidPnInterface != NULL) &&
|
|
(pCommitVidPn->hFunctionalVidPn != 0) &&
|
|
(hVidPnSourceModeSet != 0))
|
|
{
|
|
TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pCommitVidPn->hFunctionalVidPn, hVidPnSourceModeSet);
|
|
NT_ASSERT(NT_SUCCESS(TempStatus));
|
|
}
|
|
|
|
if ((pVidPnTopologyInterface != NULL) &&
|
|
(hVidPnTopology != 0) &&
|
|
(pVidPnPresentPath != NULL))
|
|
{
|
|
TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);
|
|
NT_ASSERT(NT_SUCCESS(TempStatus));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
BDD_ASSERT(pUpdateActiveVidPnPresentPath != NULL);
|
|
|
|
NTSTATUS Status = IsVidPnPathFieldsValid(&(pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
// Mark the next present as fullscreen to make sure the full rotation comes through
|
|
m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Flags.FullscreenPresent = TRUE;
|
|
|
|
m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Rotation = pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.ContentTransformation.Rotation;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Private BDD DMM functions
|
|
//
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode,
|
|
CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
CURRENT_BDD_MODE* pCurrentBddMode = &m_CurrentModes[pPath->VidPnSourceId];
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
pCurrentBddMode->Scaling = pPath->ContentTransformation.Scaling;
|
|
pCurrentBddMode->SrcModeWidth = pSourceMode->Format.Graphics.PrimSurfSize.cx;
|
|
pCurrentBddMode->SrcModeHeight = pSourceMode->Format.Graphics.PrimSurfSize.cy;
|
|
pCurrentBddMode->Rotation = pPath->ContentTransformation.Rotation;
|
|
|
|
|
|
if (!pCurrentBddMode->Flags.DoNotMapOrUnmap)
|
|
{
|
|
// Map the new frame buffer
|
|
BDD_ASSERT(pCurrentBddMode->FrameBuffer.Ptr == NULL);
|
|
Status = MapFrameBuffer(pCurrentBddMode->DispInfo.PhysicAddress,
|
|
pCurrentBddMode->DispInfo.Pitch * pCurrentBddMode->DispInfo.Height,
|
|
&(pCurrentBddMode->FrameBuffer.Ptr));
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
|
|
pCurrentBddMode->Flags.FrameBufferIsActive = TRUE;
|
|
BlackOutScreen(pPath->VidPnSourceId);
|
|
|
|
// Mark that the next present should be fullscreen so the screen doesn't go from black to actual pixels one dirty rect at a time.
|
|
pCurrentBddMode->Flags.FullscreenPresent = TRUE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (pPath->VidPnSourceId >= MAX_VIEWS)
|
|
{
|
|
BDD_LOG_ERROR2("VidPnSourceId is 0x%I64x is too high (MAX_VIEWS is 0x%I64x)",
|
|
pPath->VidPnSourceId, MAX_VIEWS);
|
|
return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE;
|
|
}
|
|
else if (pPath->VidPnTargetId >= MAX_CHILDREN)
|
|
{
|
|
BDD_LOG_ERROR2("VidPnTargetId is 0x%I64x is too high (MAX_CHILDREN is 0x%I64x)",
|
|
pPath->VidPnTargetId, MAX_CHILDREN);
|
|
return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET;
|
|
}
|
|
else if (pPath->GammaRamp.Type != D3DDDI_GAMMARAMP_DEFAULT)
|
|
{
|
|
BDD_LOG_ERROR1("pPath contains a gamma ramp (0x%I64x)", pPath->GammaRamp.Type);
|
|
return STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED;
|
|
}
|
|
else if ((pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_IDENTITY) &&
|
|
(pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_CENTERED) &&
|
|
(pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_NOTSPECIFIED) &&
|
|
(pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_UNINITIALIZED))
|
|
{
|
|
BDD_LOG_ERROR1("pPath contains a non-identity scaling (0x%I64x)", pPath->ContentTransformation.Scaling);
|
|
return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED;
|
|
}
|
|
else if ((pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_IDENTITY) &&
|
|
(pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_ROTATE90) &&
|
|
(pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_NOTSPECIFIED) &&
|
|
(pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_UNINITIALIZED))
|
|
{
|
|
BDD_LOG_ERROR1("pPath contains a not-supported rotation (0x%I64x)", pPath->ContentTransformation.Rotation);
|
|
return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED;
|
|
}
|
|
else if ((pPath->VidPnTargetColorBasis != D3DKMDT_CB_SCRGB) &&
|
|
(pPath->VidPnTargetColorBasis != D3DKMDT_CB_UNINITIALIZED))
|
|
{
|
|
BDD_LOG_ERROR1("pPath has a non-linear RGB color basis (0x%I64x)", pPath->VidPnTargetColorBasis);
|
|
return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
|
|
}
|
|
else
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (pSourceMode->Type != D3DKMDT_RMT_GRAPHICS)
|
|
{
|
|
BDD_LOG_ERROR1("pSourceMode is a non-graphics mode (0x%I64x)", pSourceMode->Type);
|
|
return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
|
|
}
|
|
else if ((pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_SCRGB) &&
|
|
(pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_UNINITIALIZED))
|
|
{
|
|
BDD_LOG_ERROR1("pSourceMode has a non-linear RGB color basis (0x%I64x)", pSourceMode->Format.Graphics.ColorBasis);
|
|
return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
|
|
}
|
|
else if (pSourceMode->Format.Graphics.PixelValueAccessMode != D3DKMDT_PVAM_DIRECT)
|
|
{
|
|
BDD_LOG_ERROR1("pSourceMode has a palettized access mode (0x%I64x)", pSourceMode->Format.Graphics.PixelValueAccessMode);
|
|
return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
|
|
}
|
|
else
|
|
{
|
|
for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx)
|
|
{
|
|
if (pSourceMode->Format.Graphics.PixelFormat == gBddPixelFormats[PelFmtIdx])
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
BDD_LOG_ERROR1("pSourceMode has an unknown pixel format (0x%I64x)", pSourceMode->Format.Graphics.PixelFormat);
|
|
return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Add more mode from the table.
|
|
struct SampleSourceMode
|
|
{
|
|
UINT ModeWidth;
|
|
UINT ModeHeight;
|
|
};
|
|
|
|
// The driver will advertise all modes that fit within the actual required mode (see AddSingleSourceMode below)
|
|
const static SampleSourceMode C_SampleSourceMode[] = {{800,600},{1024,768},{1152,864},{1280,800},{1280,1024},{1400,1050},{1600,1200},{1680,1050},{1920,1200}};
|
|
const static UINT C_SampleSourceModeMax = sizeof(C_SampleSourceMode)/sizeof(C_SampleSourceMode[0]);
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface,
|
|
D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet,
|
|
D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
// There is only one source format supported by display-only drivers, but more can be added in a
|
|
// full WDDM driver if the hardware supports them
|
|
for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx)
|
|
{
|
|
// Create new mode info that will be populated
|
|
D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL;
|
|
NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
// If failed to create a new mode info, mode doesn't need to be released since it was never created
|
|
BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet);
|
|
return Status;
|
|
}
|
|
|
|
// Populate mode info with values from current mode and hard-coded values
|
|
// Always report 32 bpp format, this will be color converted during the present if the mode is < 32bpp
|
|
pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS;
|
|
pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = m_CurrentModes[SourceId].DispInfo.Width;
|
|
pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = m_CurrentModes[SourceId].DispInfo.Height;
|
|
pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize;
|
|
pVidPnSourceModeInfo->Format.Graphics.Stride = m_CurrentModes[SourceId].DispInfo.Pitch;
|
|
pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx];
|
|
pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB;
|
|
pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT;
|
|
|
|
// Add the mode to the source mode set
|
|
Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
// If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
|
|
NTSTATUS TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo);
|
|
UNREFERENCED_PARAMETER(TempStatus);
|
|
NT_ASSERT(NT_SUCCESS(TempStatus));
|
|
|
|
if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
|
|
{
|
|
BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo);
|
|
return Status;
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT WidthMax = m_CurrentModes[SourceId].DispInfo.Width;
|
|
UINT HeightMax = m_CurrentModes[SourceId].DispInfo.Height;
|
|
|
|
// Add all predefined modes that fit within the bounds of the required (POST) mode
|
|
for (UINT ModeIndex = 0; ModeIndex < C_SampleSourceModeMax; ++ModeIndex)
|
|
{
|
|
if (C_SampleSourceMode[ModeIndex].ModeWidth > WidthMax)
|
|
{
|
|
break;
|
|
}
|
|
else if (C_SampleSourceMode[ModeIndex].ModeWidth == WidthMax)
|
|
{
|
|
if(C_SampleSourceMode[ModeIndex].ModeHeight >= HeightMax)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(C_SampleSourceMode[ModeIndex].ModeHeight > HeightMax)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// There is only one source format supported by display-only drivers, but more can be added in a
|
|
// full WDDM driver if the hardware supports them
|
|
for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx)
|
|
{
|
|
// Create new mode info that will be populated
|
|
D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL;
|
|
NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
// If failed to create a new mode info, continuing to the next mode and trying again isn't going to be at all helpful, so return
|
|
// Also, mode doesn't need to be released since it was never created
|
|
BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet);
|
|
return Status;
|
|
}
|
|
|
|
// Populate mode info with values from mode at ModeIndex and hard-coded values
|
|
// Always report 32 bpp format, this will be color converted during the present if the mode at ModeIndex was < 32bpp
|
|
pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS;
|
|
pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = C_SampleSourceMode[ModeIndex].ModeWidth;
|
|
pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = C_SampleSourceMode[ModeIndex].ModeHeight;
|
|
pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize;
|
|
pVidPnSourceModeInfo->Format.Graphics.Stride = 4*C_SampleSourceMode[ModeIndex].ModeWidth;
|
|
pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx];
|
|
pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB;
|
|
pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT;
|
|
|
|
// Add the mode to the source mode set
|
|
Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
|
|
{
|
|
BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo);
|
|
}
|
|
|
|
// If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked, continue to next mode anyway
|
|
Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo);
|
|
BDD_ASSERT_CHK(NT_SUCCESS(Status));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
// Add the current mode information (acquired from the POST frame buffer) as the target mode.
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface,
|
|
D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet,
|
|
_In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo,
|
|
D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
D3DKMDT_VIDPN_TARGET_MODE* pVidPnTargetModeInfo = NULL;
|
|
NTSTATUS Status = pVidPnTargetModeSetInterface->pfnCreateNewModeInfo(hVidPnTargetModeSet, &pVidPnTargetModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
// If failed to create a new mode info, mode doesn't need to be released since it was never created
|
|
BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet);
|
|
return Status;
|
|
}
|
|
|
|
pVidPnTargetModeInfo->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER;
|
|
UNREFERENCED_PARAMETER(pVidPnPinnedSourceModeInfo);
|
|
pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cx = m_CurrentModes[SourceId].DispInfo.Width;
|
|
pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cy = m_CurrentModes[SourceId].DispInfo.Height;
|
|
pVidPnTargetModeInfo->VideoSignalInfo.ActiveSize = pVidPnTargetModeInfo->VideoSignalInfo.TotalSize;
|
|
pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pVidPnTargetModeInfo->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pVidPnTargetModeInfo->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE;
|
|
// We add this as PREFERRED since it is the only supported target
|
|
pVidPnTargetModeInfo->Preference = D3DKMDT_MP_PREFERRED;
|
|
|
|
Status = pVidPnTargetModeSetInterface->pfnAddMode(hVidPnTargetModeSet, pVidPnTargetModeInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
|
|
{
|
|
BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnTargetModeInfo = 0x%I64x", Status, hVidPnTargetModeSet, pVidPnTargetModeInfo);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
// If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
|
|
NTSTATUS TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnTargetModeInfo);
|
|
UNREFERENCED_PARAMETER(TempStatus);
|
|
NT_ASSERT(NT_SUCCESS(TempStatus));
|
|
return Status;
|
|
}
|
|
else
|
|
{
|
|
// If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
D3DKMDT_MONITOR_SOURCE_MODE* pMonitorSourceMode = NULL;
|
|
NTSTATUS Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
// If failed to create a new mode info, mode doesn't need to be released since it was never created
|
|
BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet);
|
|
return Status;
|
|
}
|
|
|
|
D3DDDI_VIDEO_PRESENT_SOURCE_ID CorrespondingSourceId = FindSourceForTarget(pRecommendMonitorModes->VideoPresentTargetId, TRUE);
|
|
|
|
// Since we don't know the real monitor timing information, just use the current display mode (from the POST device) with unknown frequencies
|
|
pMonitorSourceMode->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER;
|
|
pMonitorSourceMode->VideoSignalInfo.TotalSize.cx = m_CurrentModes[CorrespondingSourceId].DispInfo.Width;
|
|
pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = m_CurrentModes[CorrespondingSourceId].DispInfo.Height;
|
|
pMonitorSourceMode->VideoSignalInfo.ActiveSize = pMonitorSourceMode->VideoSignalInfo.TotalSize;
|
|
pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pMonitorSourceMode->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED;
|
|
pMonitorSourceMode->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE;
|
|
|
|
// We set the preference to PREFERRED since this is the only supported mode
|
|
pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER;
|
|
pMonitorSourceMode->Preference = D3DKMDT_MP_PREFERRED;
|
|
pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB;
|
|
pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8;
|
|
pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8;
|
|
pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8;
|
|
pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8;
|
|
|
|
Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
|
|
{
|
|
BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x",
|
|
Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
// If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
|
|
NTSTATUS TempStatus = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
|
|
UNREFERENCED_PARAMETER(TempStatus);
|
|
NT_ASSERT(NT_SUCCESS(TempStatus));
|
|
return Status;
|
|
}
|
|
else
|
|
{
|
|
// If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|