Files

855 lines
31 KiB
C++

/******************************Module*Header*******************************\
* Module Name: bdd.cxx
*
* Basic Display Driver functions implementation
*
*
* Copyright (c) 2010 Microsoft Corporation
\**************************************************************************/
#include "BDD.hxx"
#pragma code_seg("PAGE")
BASIC_DISPLAY_DRIVER::BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pPhysicalDeviceObject),
m_MonitorPowerState(PowerDeviceD0),
m_AdapterPowerState(PowerDeviceD0)
{
PAGED_CODE();
*((UINT*)&m_Flags) = 0;
m_Flags._LastFlag = TRUE;
RtlZeroMemory(&m_DxgkInterface, sizeof(m_DxgkInterface));
RtlZeroMemory(&m_StartInfo, sizeof(m_StartInfo));
RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));
RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo));
for (UINT i=0;i<MAX_VIEWS;i++)
{
m_HardwareBlt[i].Initialize(this,i);
}
}
BASIC_DISPLAY_DRIVER::~BASIC_DISPLAY_DRIVER()
{
PAGED_CODE();
CleanUp();
}
NTSTATUS BASIC_DISPLAY_DRIVER::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo,
_In_ DXGKRNL_INTERFACE* pDxgkInterface,
_Out_ ULONG* pNumberOfViews,
_Out_ ULONG* pNumberOfChildren)
{
PAGED_CODE();
BDD_ASSERT(pDxgkStartInfo != NULL);
BDD_ASSERT(pDxgkInterface != NULL);
BDD_ASSERT(pNumberOfViews != NULL);
BDD_ASSERT(pNumberOfChildren != NULL);
RtlCopyMemory(&m_StartInfo, pDxgkStartInfo, sizeof(m_StartInfo));
RtlCopyMemory(&m_DxgkInterface, pDxgkInterface, sizeof(m_DxgkInterface));
RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));
m_CurrentModes[0].DispInfo.TargetId = D3DDDI_ID_UNINITIALIZED;
// Get device information from OS.
NTSTATUS Status = m_DxgkInterface.DxgkCbGetDeviceInformation(m_DxgkInterface.DeviceHandle, &m_DeviceInfo);
if (!NT_SUCCESS(Status))
{
BDD_LOG_ASSERTION1("DxgkCbGetDeviceInformation failed with status 0x%I64x",
Status);
return Status;
}
// Ignore return value, since it's not the end of the world if we failed to write these values to the registry
RegisterHWInfo();
// TODO: Uncomment the line below after updating the TODOs in the function CheckHardware
// Status = CheckHardware();
if (!NT_SUCCESS(Status))
{
return Status;
}
// This sample driver only uses the frame buffer of the POST device. DxgkCbAcquirePostDisplayOwnership
// gives you the frame buffer address and ensures that no one else is drawing to it. Be sure to give it back!
Status = m_DxgkInterface.DxgkCbAcquirePostDisplayOwnership(m_DxgkInterface.DeviceHandle, &(m_CurrentModes[0].DispInfo));
if (!NT_SUCCESS(Status) || m_CurrentModes[0].DispInfo.Width == 0)
{
// The most likely cause of failure is that the driver is simply not running on a POST device, or we are running
// after a pre-WDDM 1.2 driver. Since we can't draw anything, we should fail to start.
return STATUS_UNSUCCESSFUL;
}
m_Flags.DriverStarted = TRUE;
*pNumberOfViews = MAX_VIEWS;
*pNumberOfChildren = MAX_CHILDREN;
return STATUS_SUCCESS;
}
NTSTATUS BASIC_DISPLAY_DRIVER::StopDevice(VOID)
{
PAGED_CODE();
CleanUp();
m_Flags.DriverStarted = FALSE;
return STATUS_SUCCESS;
}
VOID BASIC_DISPLAY_DRIVER::CleanUp()
{
PAGED_CODE();
for (UINT Source = 0; Source < MAX_VIEWS; ++Source)
{
if (m_CurrentModes[Source].FrameBuffer.Ptr)
{
UnmapFrameBuffer(m_CurrentModes[Source].FrameBuffer.Ptr, m_CurrentModes[Source].DispInfo.Height * m_CurrentModes[Source].DispInfo.Pitch);
m_CurrentModes[Source].FrameBuffer.Ptr = NULL;
m_CurrentModes[Source].Flags.FrameBufferIsActive = FALSE;
}
}
}
NTSTATUS BASIC_DISPLAY_DRIVER::DispatchIoRequest(_In_ ULONG VidPnSourceId,
_In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket)
{
PAGED_CODE();
BDD_ASSERT(pVideoRequestPacket != NULL);
BDD_ASSERT(VidPnSourceId < MAX_VIEWS);
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS BASIC_DISPLAY_DRIVER::SetPowerState(_In_ ULONG HardwareUid,
_In_ DEVICE_POWER_STATE DevicePowerState,
_In_ POWER_ACTION ActionType)
{
PAGED_CODE();
UNREFERENCED_PARAMETER(ActionType);
BDD_ASSERT((HardwareUid < MAX_CHILDREN) || (HardwareUid == DISPLAY_ADAPTER_HW_ID));
if (HardwareUid == DISPLAY_ADAPTER_HW_ID)
{
if (DevicePowerState == PowerDeviceD0)
{
// When returning from D3 the device visibility defined to be off for all targets
if (m_AdapterPowerState == PowerDeviceD3)
{
DXGKARG_SETVIDPNSOURCEVISIBILITY Visibility;
Visibility.VidPnSourceId = D3DDDI_ID_ALL;
Visibility.Visible = FALSE;
SetVidPnSourceVisibility(&Visibility);
}
}
// Store new adapter power state
m_AdapterPowerState = DevicePowerState;
// There is nothing to do to specifically power up/down the display adapter
return STATUS_SUCCESS;
}
else
{
// TODO: This is where the specified monitor should be powered up/down
NOTHING;
return STATUS_SUCCESS;
}
}
NTSTATUS BASIC_DISPLAY_DRIVER::QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,
_In_ ULONG ChildRelationsSize)
{
PAGED_CODE();
BDD_ASSERT(pChildRelations != NULL);
// The last DXGK_CHILD_DESCRIPTOR in the array of pChildRelations must remain zeroed out, so we subtract this from the count
ULONG ChildRelationsCount = (ChildRelationsSize / sizeof(DXGK_CHILD_DESCRIPTOR)) - 1;
BDD_ASSERT(ChildRelationsCount <= MAX_CHILDREN);
for (UINT ChildIndex = 0; ChildIndex < ChildRelationsCount; ++ChildIndex)
{
pChildRelations[ChildIndex].ChildDeviceType = TypeVideoOutput;
pChildRelations[ChildIndex].ChildCapabilities.HpdAwareness = HpdAwarenessInterruptible;
pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.InterfaceTechnology = m_CurrentModes[0].Flags.IsInternal ? D3DKMDT_VOT_INTERNAL : D3DKMDT_VOT_OTHER;
pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.MonitorOrientationAwareness = D3DKMDT_MOA_NONE;
pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.SupportsSdtvModes = FALSE;
// TODO: Replace 0 with the actual ACPI ID of the child device, if available
pChildRelations[ChildIndex].AcpiUid = 0;
pChildRelations[ChildIndex].ChildUid = ChildIndex;
}
return STATUS_SUCCESS;
}
NTSTATUS BASIC_DISPLAY_DRIVER::QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus,
_In_ BOOLEAN NonDestructiveOnly)
{
PAGED_CODE();
UNREFERENCED_PARAMETER(NonDestructiveOnly);
BDD_ASSERT(pChildStatus != NULL);
BDD_ASSERT(pChildStatus->ChildUid < MAX_CHILDREN);
switch (pChildStatus->Type)
{
case StatusConnection:
{
// HpdAwarenessInterruptible was reported since HpdAwarenessNone is deprecated.
// However, BDD has no knowledge of HotPlug events, so just always return connected.
pChildStatus->HotPlug.Connected = IsDriverActive();
return STATUS_SUCCESS;
}
case StatusRotation:
{
// D3DKMDT_MOA_NONE was reported, so this should never be called
BDD_LOG_ERROR0("Child status being queried for StatusRotation even though D3DKMDT_MOA_NONE was reported");
return STATUS_INVALID_PARAMETER;
}
default:
{
BDD_LOG_WARNING1("Unknown pChildStatus->Type (0x%I64x) requested.", pChildStatus->Type);
return STATUS_NOT_SUPPORTED;
}
}
}
// EDID retrieval
NTSTATUS BASIC_DISPLAY_DRIVER::QueryDeviceDescriptor(_In_ ULONG ChildUid,
_Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor)
{
PAGED_CODE();
BDD_ASSERT(pDeviceDescriptor != NULL);
BDD_ASSERT(ChildUid < MAX_CHILDREN);
// If we haven't successfully retrieved an EDID yet (invalid ones are ok, so long as it was retrieved)
if (!m_Flags.EDID_Attempted)
{
GetEdid(ChildUid);
}
if (!m_Flags.EDID_Retrieved || !m_Flags.EDID_ValidHeader || !m_Flags.EDID_ValidChecksum)
{
// Report no EDID if a valid one wasn't retrieved
return STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED;
}
else if (pDeviceDescriptor->DescriptorOffset == 0)
{
// Only the base block is supported
RtlCopyMemory(pDeviceDescriptor->DescriptorBuffer,
m_EDIDs[ChildUid],
min(pDeviceDescriptor->DescriptorLength, EDID_V1_BLOCK_SIZE));
return STATUS_SUCCESS;
}
else
{
return STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA;
}
}
NTSTATUS BASIC_DISPLAY_DRIVER::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo)
{
PAGED_CODE();
BDD_ASSERT(pQueryAdapterInfo != NULL);
switch (pQueryAdapterInfo->Type)
{
case DXGKQAITYPE_DRIVERCAPS:
{
if (pQueryAdapterInfo->OutputDataSize < sizeof(DXGK_DRIVERCAPS))
{
BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DRIVERCAPS) (0x%I64x)", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_DRIVERCAPS));
return STATUS_BUFFER_TOO_SMALL;
}
DXGK_DRIVERCAPS* pDriverCaps = (DXGK_DRIVERCAPS*)pQueryAdapterInfo->pOutputData;
// Nearly all fields must be initialized to zero, so zero out to start and then change those that are non-zero.
// Fields are zero since BDD is Display-Only and therefore does not support any of the render related fields.
// It also doesn't support hardware interrupts, gamma ramps, etc.
RtlZeroMemory(pDriverCaps, sizeof(DXGK_DRIVERCAPS));
pDriverCaps->WDDMVersion = DXGKDDI_WDDMv1_2;
pDriverCaps->HighestAcceptableAddress.QuadPart = -1;
pDriverCaps->SupportNonVGA = TRUE;
pDriverCaps->SupportSmoothRotation = TRUE;
return STATUS_SUCCESS;
}
case DXGKQAITYPE_DISPLAY_DRIVERCAPS_EXTENSION:
{
DXGK_DISPLAY_DRIVERCAPS_EXTENSION* pDriverDisplayCaps;
if (pQueryAdapterInfo->OutputDataSize < sizeof(*pDriverDisplayCaps))
{
BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION) (0x%I64x)",
pQueryAdapterInfo->OutputDataSize,
sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION));
return STATUS_INVALID_PARAMETER;
}
pDriverDisplayCaps = (DXGK_DISPLAY_DRIVERCAPS_EXTENSION*)pQueryAdapterInfo->pOutputData;
// Reset all caps values
RtlZeroMemory(pDriverDisplayCaps, pQueryAdapterInfo->OutputDataSize);
// We claim to support virtual display mode.
pDriverDisplayCaps->VirtualModeSupport = 1;
return STATUS_SUCCESS;
}
default:
{
// BDD does not need to support any other adapter information types
BDD_LOG_WARNING1("Unknown QueryAdapterInfo Type (0x%I64x) requested", pQueryAdapterInfo->Type);
return STATUS_NOT_SUPPORTED;
}
}
}
NTSTATUS BASIC_DISPLAY_DRIVER::CheckHardware()
{
PAGED_CODE();
NTSTATUS Status;
ULONG VendorID;
ULONG DeviceID;
// TODO: If developing a driver for PCI based hardware, then use the second method to retrieve Vendor/Device IDs.
// If developing for non-PCI based hardware (i.e. ACPI based hardware), use the first method to retrieve the IDs.
#if 1 // ACPI-based device
// Get the Vendor & Device IDs on non-PCI system
ACPI_EVAL_INPUT_BUFFER_COMPLEX AcpiInputBuffer = {0};
AcpiInputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
AcpiInputBuffer.MethodNameAsUlong = ACPI_METHOD_HARDWARE_ID;
AcpiInputBuffer.Size = 0;
AcpiInputBuffer.ArgumentCount = 0;
BYTE OutputBuffer[sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 0x10];
RtlZeroMemory(OutputBuffer, sizeof(OutputBuffer));
ACPI_EVAL_OUTPUT_BUFFER* pAcpiOutputBuffer = reinterpret_cast<ACPI_EVAL_OUTPUT_BUFFER*>(&OutputBuffer);
Status = m_DxgkInterface.DxgkCbEvalAcpiMethod(m_DxgkInterface.DeviceHandle,
DISPLAY_ADAPTER_HW_ID,
&AcpiInputBuffer,
sizeof(AcpiInputBuffer),
pAcpiOutputBuffer,
sizeof(OutputBuffer));
if (!NT_SUCCESS(Status))
{
BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed to get hardware IDs with status 0x%I64x", Status);
return Status;
}
VendorID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[0];
DeviceID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[1];
#else // PCI-based device
// Get the Vendor & Device IDs on PCI system
PCI_COMMON_HEADER Header = {0};
ULONG BytesRead;
Status = m_DxgkInterface.DxgkCbReadDeviceSpace(m_DxgkInterface.DeviceHandle,
DXGK_WHICHSPACE_CONFIG,
&Header,
0,
sizeof(Header),
&BytesRead);
if (!NT_SUCCESS(Status))
{
BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed with status 0x%I64x", Status);
return Status;
}
VendorID = Header.VendorID;
DeviceID = Header.DeviceID;
#endif
// TODO: Replace 0x1414 with your Vendor ID
if (VendorID == 0x1414)
{
switch (DeviceID)
{
// TODO: Replace the case statements below with the Device IDs supported by this driver
case 0x0000:
case 0xFFFF: return STATUS_SUCCESS;
}
}
return STATUS_GRAPHICS_DRIVER_MISMATCH;
}
// Even though Sample Basic Display Driver does not support hardware cursors, and reports such
// in QueryAdapterInfo. This function can still be called to set the pointer to not visible
NTSTATUS BASIC_DISPLAY_DRIVER::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
{
PAGED_CODE();
BDD_ASSERT(pSetPointerPosition != NULL);
BDD_ASSERT(pSetPointerPosition->VidPnSourceId < MAX_VIEWS);
if (!(pSetPointerPosition->Flags.Visible))
{
return STATUS_SUCCESS;
}
else
{
BDD_LOG_ASSERTION0("SetPointerPosition should never be called to set the pointer to visible since BDD doesn't support hardware cursors.");
return STATUS_UNSUCCESSFUL;
}
}
// Basic Sample Display Driver does not support hardware cursors, and reports such
// in QueryAdapterInfo. Therefore this function should never be called.
NTSTATUS BASIC_DISPLAY_DRIVER::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
{
PAGED_CODE();
BDD_ASSERT(pSetPointerShape != NULL);
BDD_LOG_ASSERTION0("SetPointerShape should never be called since BDD doesn't support hardware cursors.");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS BASIC_DISPLAY_DRIVER::PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly)
{
PAGED_CODE();
BDD_ASSERT(pPresentDisplayOnly != NULL);
BDD_ASSERT(pPresentDisplayOnly->VidPnSourceId < MAX_VIEWS);
if (pPresentDisplayOnly->BytesPerPixel < MIN_BYTES_PER_PIXEL_REPORTED)
{
// Only >=32bpp modes are reported, therefore this Present should never pass anything less than 4 bytes per pixel
BDD_LOG_ERROR1("pPresentDisplayOnly->BytesPerPixel is 0x%I64x, which is lower than the allowed.", pPresentDisplayOnly->BytesPerPixel);
return STATUS_INVALID_PARAMETER;
}
// If it is in monitor off state or source is not supposed to be visible, don't present anything to the screen
if ((m_MonitorPowerState > PowerDeviceD0) ||
(m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.SourceNotVisible))
{
return STATUS_SUCCESS;
}
// Present is only valid if the target is actively connected to this source
if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.FrameBufferIsActive)
{
// If actual pixels are coming through, will need to completely zero out physical address next time in BlackOutScreen
m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutStart.QuadPart = 0;
m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutEnd.QuadPart = 0;
D3DKMDT_VIDPN_PRESENT_PATH_ROTATION RotationNeededByFb = pPresentDisplayOnly->Flags.Rotate ?
m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Rotation :
D3DKMDT_VPPR_IDENTITY;
BYTE* pDst = (BYTE*)m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].FrameBuffer.Ptr;
UINT DstBitPerPixel = BPPFromPixelFormat(m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.ColorFormat);
if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Scaling == D3DKMDT_VPPS_CENTERED)
{
UINT CenterShift = (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Height -
m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeHeight)*m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Pitch;
CenterShift += (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Width -
m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeWidth)*DstBitPerPixel/8;
pDst += (int)CenterShift/2;
}
return m_HardwareBlt[pPresentDisplayOnly->VidPnSourceId].ExecutePresentDisplayOnly(pDst,
DstBitPerPixel,
(BYTE*)pPresentDisplayOnly->pSource,
pPresentDisplayOnly->BytesPerPixel,
pPresentDisplayOnly->Pitch,
pPresentDisplayOnly->NumMoves,
pPresentDisplayOnly->pMoves,
pPresentDisplayOnly->NumDirtyRects,
pPresentDisplayOnly->pDirtyRect,
RotationNeededByFb);
}
return STATUS_SUCCESS;
}
NTSTATUS BASIC_DISPLAY_DRIVER::StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
_Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo)
{
PAGED_CODE();
BDD_ASSERT(TargetId < MAX_CHILDREN);
D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = FindSourceForTarget(TargetId, TRUE);
// In case BDD is the next driver to run, the monitor should not be off, since
// this could cause the BIOS to hang when the EDID is retrieved on Start.
if (m_MonitorPowerState > PowerDeviceD0)
{
SetPowerState(TargetId, PowerDeviceD0, PowerActionNone);
}
// The driver has to black out the display and ensure it is visible when releasing ownership
BlackOutScreen(SourceId);
*pDisplayInfo = m_CurrentModes[SourceId].DispInfo;
return StopDevice();
}
NTSTATUS BASIC_DISPLAY_DRIVER::QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps)
{
PAGED_CODE();
BDD_ASSERT(pVidPnHWCaps != NULL);
BDD_ASSERT(pVidPnHWCaps->SourceId < MAX_VIEWS);
BDD_ASSERT(pVidPnHWCaps->TargetId < MAX_CHILDREN);
pVidPnHWCaps->VidPnHWCaps.DriverRotation = 1; // BDD does rotation in software
pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0; // BDD does not support scaling
pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0; // BDD does not support clone
pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 1; // BDD does color conversions in software
pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0; // BDD does not support linked adapters
pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0; // BDD does not support remote displays
return STATUS_SUCCESS;
}
NTSTATUS BASIC_DISPLAY_DRIVER::GetEdid(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId)
{
PAGED_CODE();
BDD_ASSERT_CHK(!m_Flags.EDID_Attempted);
NTSTATUS Status = STATUS_SUCCESS;
RtlZeroMemory(m_EDIDs[TargetId], sizeof(m_EDIDs[TargetId]));
m_Flags.EDID_Attempted = TRUE;
return Status;
}
VOID BASIC_DISPLAY_DRIVER::BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId)
{
PAGED_CODE();
UINT ScreenHeight = m_CurrentModes[SourceId].DispInfo.Height;
UINT ScreenPitch = m_CurrentModes[SourceId].DispInfo.Pitch;
PHYSICAL_ADDRESS NewPhysAddrStart = m_CurrentModes[SourceId].DispInfo.PhysicAddress;
PHYSICAL_ADDRESS NewPhysAddrEnd;
NewPhysAddrEnd.QuadPart = NewPhysAddrStart.QuadPart + (ScreenHeight * ScreenPitch);
if (m_CurrentModes[SourceId].Flags.FrameBufferIsActive)
{
BYTE* MappedAddr = reinterpret_cast<BYTE*>(m_CurrentModes[SourceId].FrameBuffer.Ptr);
// Zero any memory at the start that hasn't been zeroed recently
if (NewPhysAddrStart.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart)
{
if (NewPhysAddrEnd.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart)
{
// No overlap
RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch);
}
else
{
RtlZeroMemory(MappedAddr, (UINT)(m_CurrentModes[SourceId].ZeroedOutStart.QuadPart - NewPhysAddrStart.QuadPart));
}
}
// Zero any memory at the end that hasn't been zeroed recently
if (NewPhysAddrEnd.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart)
{
if (NewPhysAddrStart.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart)
{
// No overlap
// NOTE: When actual pixels were the most recent thing drawn, ZeroedOutStart & ZeroedOutEnd will both be 0
// and this is the path that will be used to black out the current screen.
RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch);
}
else
{
RtlZeroMemory(MappedAddr, (UINT)(NewPhysAddrEnd.QuadPart - m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart));
}
}
}
m_CurrentModes[SourceId].ZeroedOutStart.QuadPart = NewPhysAddrStart.QuadPart;
m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart = NewPhysAddrEnd.QuadPart;
}
NTSTATUS BASIC_DISPLAY_DRIVER::WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue)
{
PAGED_CODE();
NTSTATUS Status;
ANSI_STRING AnsiStrValue;
UNICODE_STRING UnicodeStrValue;
UNICODE_STRING UnicodeStrValueName;
// ZwSetValueKey wants the ValueName as a UNICODE_STRING
RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName);
// REG_SZ is for WCHARs, there is no equivalent for CHARs
// Use the ansi/unicode conversion functions to get from PSTR to PWSTR
RtlInitAnsiString(&AnsiStrValue, pszValue);
Status = RtlAnsiStringToUnicodeString(&UnicodeStrValue, &AnsiStrValue, TRUE);
if (!NT_SUCCESS(Status))
{
BDD_LOG_ERROR1("RtlAnsiStringToUnicodeString failed with Status: 0x%I64x", Status);
return Status;
}
// Write the value to the registry
Status = ZwSetValueKey(DevInstRegKeyHandle,
&UnicodeStrValueName,
0,
REG_SZ,
UnicodeStrValue.Buffer,
UnicodeStrValue.MaximumLength);
// Free the earlier allocated unicode string
RtlFreeUnicodeString(&UnicodeStrValue);
if (!NT_SUCCESS(Status))
{
BDD_LOG_ERROR1("ZwSetValueKey failed with Status: 0x%I64x", Status);
}
return Status;
}
NTSTATUS BASIC_DISPLAY_DRIVER::RegisterHWInfo()
{
PAGED_CODE();
NTSTATUS Status;
// TODO: Replace these strings with proper information
PCSTR StrHWInfoChipType = "Replace with the chip name";
PCSTR StrHWInfoDacType = "Replace with the DAC name or identifier (ID)";
PCSTR StrHWInfoAdapterString = "Replace with the name of the adapter";
PCSTR StrHWInfoBiosString = "Replace with information about the BIOS";
HANDLE DevInstRegKeyHandle;
Status = IoOpenDeviceRegistryKey(m_pPhysicalDevice, PLUGPLAY_REGKEY_DRIVER, KEY_SET_VALUE, &DevInstRegKeyHandle);
if (!NT_SUCCESS(Status))
{
BDD_LOG_ERROR2("IoOpenDeviceRegistryKey failed for PDO: 0x%I64x, Status: 0x%I64x", m_pPhysicalDevice, Status);
return Status;
}
Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.ChipType", StrHWInfoChipType);
if (!NT_SUCCESS(Status))
{
return Status;
}
Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.DacType", StrHWInfoDacType);
if (!NT_SUCCESS(Status))
{
return Status;
}
Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.AdapterString", StrHWInfoAdapterString);
if (!NT_SUCCESS(Status))
{
return Status;
}
Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.BiosString", StrHWInfoBiosString);
if (!NT_SUCCESS(Status))
{
return Status;
}
// MemorySize is a ULONG, unlike the others which are all strings
UNICODE_STRING ValueNameMemorySize;
RtlInitUnicodeString(&ValueNameMemorySize, L"HardwareInformation.MemorySize");
DWORD MemorySize = 0; // BDD has no access to video memory
Status = ZwSetValueKey(DevInstRegKeyHandle,
&ValueNameMemorySize,
0,
REG_DWORD,
&MemorySize,
sizeof(MemorySize));
if (!NT_SUCCESS(Status))
{
BDD_LOG_ERROR1("ZwSetValueKey for MemorySize failed with Status: 0x%I64x", Status);
return Status;
}
return Status;
}
//
// Non-Paged Code
//
#pragma code_seg(push)
#pragma code_seg()
D3DDDI_VIDEO_PRESENT_SOURCE_ID BASIC_DISPLAY_DRIVER::FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero)
{
UNREFERENCED_PARAMETER(TargetId);
BDD_ASSERT_CHK(TargetId < MAX_CHILDREN);
for (UINT SourceId = 0; SourceId < MAX_VIEWS; ++SourceId)
{
if (m_CurrentModes[SourceId].FrameBuffer.Ptr != NULL)
{
return SourceId;
}
}
return DefaultToZero ? 0 : D3DDDI_ID_UNINITIALIZED;
}
VOID BASIC_DISPLAY_DRIVER::DpcRoutine(VOID)
{
m_DxgkInterface.DxgkCbNotifyDpc((HANDLE)m_DxgkInterface.DeviceHandle);
}
BOOLEAN BASIC_DISPLAY_DRIVER::InterruptRoutine(_In_ ULONG MessageNumber)
{
UNREFERENCED_PARAMETER(MessageNumber);
// BDD cannot handle interrupts
return FALSE;
}
VOID BASIC_DISPLAY_DRIVER::ResetDevice(VOID)
{
}
// Must be Non-Paged, as it sets up the display for a bugcheck
NTSTATUS BASIC_DISPLAY_DRIVER::SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
_In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
_Out_ UINT* pWidth,
_Out_ UINT* pHeight,
_Out_ D3DDDIFORMAT* pColorFormat)
{
UNREFERENCED_PARAMETER(Flags);
m_SystemDisplaySourceId = D3DDDI_ID_UNINITIALIZED;
BDD_ASSERT((TargetId < MAX_CHILDREN) || (TargetId == D3DDDI_ID_UNINITIALIZED));
// Find the frame buffer for displaying the bugcheck, if it was successfully mapped
if (TargetId == D3DDDI_ID_UNINITIALIZED)
{
for (UINT SourceIdx = 0; SourceIdx < MAX_VIEWS; ++SourceIdx)
{
if (m_CurrentModes[SourceIdx].FrameBuffer.Ptr != NULL)
{
m_SystemDisplaySourceId = SourceIdx;
break;
}
}
}
else
{
m_SystemDisplaySourceId = FindSourceForTarget(TargetId, FALSE);
}
if (m_SystemDisplaySourceId == D3DDDI_ID_UNINITIALIZED)
{
{
return STATUS_UNSUCCESSFUL;
}
}
if ((m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE90) ||
(m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE270))
{
*pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;
*pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;
}
else
{
*pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;
*pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;
}
*pColorFormat = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat;
return STATUS_SUCCESS;
}
// Must be Non-Paged, as it is called to display the bugcheck screen
VOID BASIC_DISPLAY_DRIVER::SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource,
_In_ UINT SourceWidth,
_In_ UINT SourceHeight,
_In_ UINT SourceStride,
_In_ INT PositionX,
_In_ INT PositionY)
{
// Rect will be Offset by PositionX/Y in the src to reset it back to 0
RECT Rect;
Rect.left = PositionX;
Rect.top = PositionY;
Rect.right = Rect.left + SourceWidth;
Rect.bottom = Rect.top + SourceHeight;
// Set up destination blt info
BLT_INFO DstBltInfo;
DstBltInfo.pBits = m_CurrentModes[m_SystemDisplaySourceId].FrameBuffer.Ptr;
DstBltInfo.Pitch = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Pitch;
DstBltInfo.BitsPerPel = BPPFromPixelFormat(m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat);
DstBltInfo.Offset.x = 0;
DstBltInfo.Offset.y = 0;
DstBltInfo.Rotation = m_CurrentModes[m_SystemDisplaySourceId].Rotation;
DstBltInfo.Width = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;
DstBltInfo.Height = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;
// Set up source blt info
BLT_INFO SrcBltInfo;
SrcBltInfo.pBits = pSource;
SrcBltInfo.Pitch = SourceStride;
SrcBltInfo.BitsPerPel = 32;
SrcBltInfo.Offset.x = -PositionX;
SrcBltInfo.Offset.y = -PositionY;
SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY;
SrcBltInfo.Width = SourceWidth;
SrcBltInfo.Height = SourceHeight;
BltBits(&DstBltInfo,
&SrcBltInfo,
1, // NumRects
&Rect);
}
#pragma code_seg(pop) // End Non-Paged Code