diff --git a/qxldod/QxlDod.cpp b/qxldod/QxlDod.cpp index 9717c7d..5c7fd0a 100755 --- a/qxldod/QxlDod.cpp +++ b/qxldod/QxlDod.cpp @@ -1,6 +1,50 @@ #include "driver.h" #include "qxldod.h" +#pragma code_seg(push) +#pragma code_seg() +// BEGIN: Non-Paged Code + +// Bit is 1 from Idx to end of byte, with bit count starting at high order +BYTE lMaskTable[BITS_PER_BYTE] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +// Bit is 1 from Idx to start of byte, with bit count starting at high order +BYTE rMaskTable[BITS_PER_BYTE] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; + +// Bit of Idx is 1, with bit count starting at high order +BYTE PixelMask[BITS_PER_BYTE] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; + + +// For the following macros, pPixel must be a BYTE* pointing to the start of a 32 bit pixel +#define CONVERT_32BPP_TO_16BPP(pPixel) ((UPPER_5_BITS(pPixel[2]) << SHIFT_FOR_UPPER_5_IN_565) | \ + (UPPER_6_BITS(pPixel[1]) << SHIFT_FOR_MIDDLE_6_IN_565) | \ + (UPPER_5_BITS(pPixel[0]))) + +// 8bpp is done with 6 levels per color channel since this gives true grays, even if it leaves 40 empty palette entries +// The 6 levels per color is the reason for dividing below by 43 (43 * 6 == 258, closest multiple of 6 to 256) +// It is also the reason for multiplying the red channel by 36 (== 6*6) and the green channel by 6, as this is the +// equivalent to bit shifting in a 3:3:2 model. Changes to this must be reflected in vesasup.cxx with the Blues/Greens/Reds arrays +#define CONVERT_32BPP_TO_8BPP(pPixel) (((pPixel[2] / 43) * 36) + \ + ((pPixel[1] / 43) * 6) + \ + ((pPixel[0] / 43))) + +// 4bpp is done with strict grayscale since this has been found to be usable +// 30% of the red value, 59% of the green value, and 11% of the blue value is the standard way to convert true color to grayscale +#define CONVERT_32BPP_TO_4BPP(pPixel) ((BYTE)(((pPixel[2] * 30) + \ + (pPixel[1] * 59) + \ + (pPixel[0] * 11)) / (100 * 16))) + + +// For the following macro, Pixel must be a WORD representing a 16 bit pixel +#define CONVERT_16BPP_TO_32BPP(Pixel) (((ULONG)LOWER_5_BITS((Pixel) >> SHIFT_FOR_UPPER_5_IN_565) << SHIFT_UPPER_5_IN_565_BACK) | \ + ((ULONG)LOWER_6_BITS((Pixel) >> SHIFT_FOR_MIDDLE_6_IN_565) << SHIFT_MIDDLE_6_IN_565_BACK) | \ + ((ULONG)LOWER_5_BITS((Pixel)) << SHIFT_LOWER_5_IN_565_BACK)) + + +#pragma code_seg(pop) + + + QxlDod::QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pPhysicalDeviceObject), m_MonitorPowerState(PowerDeviceD0), m_AdapterPowerState(PowerDeviceD0) @@ -9,7 +53,8 @@ QxlDod::QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pP *((UINT*)&m_Flags) = 0; RtlZeroMemory(&m_DxgkInterface, sizeof(m_DxgkInterface)); RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo)); - + RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes)); + RtlZeroMemory(&m_PointerShape, sizeof(m_PointerShape)); DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); } @@ -19,7 +64,7 @@ QxlDod::~QxlDod(void) PAGED_CODE(); DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); -// CleanUp(); + CleanUp(); DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); } @@ -37,8 +82,9 @@ NTSTATUS QxlDod::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, QXL_ASSERT(pNumberOfChildren != NULL); DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); - DXGK_DISPLAY_INFORMATION DisplayInfo; 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)) @@ -72,11 +118,10 @@ NTSTATUS QxlDod::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, 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, &DisplayInfo); - if (!NT_SUCCESS(Status) || DisplayInfo.Width == 0) + 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. @@ -85,16 +130,15 @@ NTSTATUS QxlDod::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, *pNumberOfViews = MAX_VIEWS; *pNumberOfChildren = MAX_CHILDREN; m_Flags.DriverStarted = TRUE; - return STATUS_SUCCESS; + return STATUS_SUCCESS; } NTSTATUS QxlDod::StopDevice(VOID) { PAGED_CODE(); DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); - - DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); m_Flags.DriverStarted = FALSE; + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); return STATUS_SUCCESS; } @@ -102,7 +146,15 @@ VOID QxlDod::CleanUp(VOID) { PAGED_CODE(); DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); - DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + 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; + } + } } @@ -117,17 +169,67 @@ NTSTATUS QxlDod::DispatchIoRequest(_In_ ULONG VidPnSourceId, return STATUS_SUCCESS; } +PCHAR +DbgDevicePowerString( + __in DEVICE_POWER_STATE Type + ) +{ + switch (Type) + { + case PowerDeviceUnspecified: + return "PowerDeviceUnspecified"; + case PowerDeviceD0: + return "PowerDeviceD0"; + case PowerDeviceD1: + return "PowerDeviceD1"; + case PowerDeviceD2: + return "PowerDeviceD2"; + case PowerDeviceD3: + return "PowerDeviceD3"; + case PowerDeviceMaximum: + return "PowerDeviceMaximum"; + default: + return "UnKnown Device Power State"; + } +} + +PCHAR +DbgPowerActionString( + __in POWER_ACTION Type + ) +{ + switch (Type) + { + case PowerActionNone: + return "PowerActionNone"; + case PowerActionReserved: + return "PowerActionReserved"; + case PowerActionSleep: + return "PowerActionSleep"; + case PowerActionHibernate: + return "PowerActionHibernate"; + case PowerActionShutdown: + return "PowerActionShutdown"; + case PowerActionShutdownReset: + return "PowerActionShutdownReset"; + case PowerActionShutdownOff: + return "PowerActionShutdownOff"; + case PowerActionWarmEject: + return "PowerActionWarmEject"; + default: + return "UnKnown Device Power State"; + } +} + NTSTATUS QxlDod::SetPowerState(_In_ ULONG HardwareUid, _In_ DEVICE_POWER_STATE DevicePowerState, _In_ POWER_ACTION ActionType) { - NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); - DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s HardwareUid = 0x%x ActionType = %s DevicePowerState = %s AdapterPowerState = %s\n", __FUNCTION__, HardwareUid, DbgPowerActionString(ActionType), DbgDevicePowerString(DevicePowerState), DbgDevicePowerString(m_AdapterPowerState))); if (HardwareUid == DISPLAY_ADAPTER_HW_ID) { - if (DevicePowerState == PowerDeviceD0) { @@ -141,30 +243,17 @@ NTSTATUS QxlDod::SetPowerState(_In_ ULONG HardwareUid, } } - // Store new adapter power state m_AdapterPowerState = DevicePowerState; - } - if ((ActionType == PowerActionHibernate) && - (DevicePowerState > PowerDeviceD0)) - { - ActionType = PowerActionHibernate; + // There is nothing to do to specifically power up/down the display adapter + return STATUS_SUCCESS; } - else if ((ActionType >= PowerActionShutdown) && - (ActionType < PowerActionWarmEject) && - (DevicePowerState > PowerDeviceD0)) - { - ActionType = PowerActionShutdown; - } - - Status = VbeSetPowerState(ActionType); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); - - return Status; + // TODO: This is where the specified monitor should be powered up/down + VbeSetPowerState(ActionType); + return STATUS_SUCCESS; } - NTSTATUS QxlDod::QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, _In_ ULONG ChildRelationsSize) { @@ -263,6 +352,12 @@ NTSTATUS QxlDod::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAda pDriverCaps->WDDMVersion = DXGKDDI_WDDMv1_2; pDriverCaps->HighestAcceptableAddress.QuadPart = -1; +/* + pDriverCaps->MaxPointerWidth = 64; + pDriverCaps->MaxPointerHeight = 64; + pDriverCaps->PointerCaps.Monochrome = 1; + pDriverCaps->PointerCaps.Color = 1; +*/ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s 1\n", __FUNCTION__)); return STATUS_SUCCESS; } @@ -289,7 +384,6 @@ NTSTATUS QxlDod::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetP DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s Cursor is not visible\n", __FUNCTION__)); return STATUS_SUCCESS; } - DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s cursor position X = %d, Y = %d\n", __FUNCTION__, pSetPointerPosition->X, pSetPointerPosition->Y)); return STATUS_UNSUCCESSFUL; } @@ -300,20 +394,9 @@ NTSTATUS QxlDod::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointer PAGED_CODE(); QXL_ASSERT(pSetPointerShape != NULL); - DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s Height = %d, Width = %d, XHot= %d, YHot = %d\n", __FUNCTION__, pSetPointerShape->Height, pSetPointerShape->Width, pSetPointerShape->XHot, pSetPointerShape->YHot)); - - if (pSetPointerShape->Flags.Color) - { - } - else if (pSetPointerShape->Flags.Monochrome) - { - } - else - { - return STATUS_UNSUCCESSFUL; - } - - return STATUS_NOT_IMPLEMENTED; + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s Height = %d, Width = %d, XHot= %d, YHot = %d SourceId = %d\n", + __FUNCTION__, pSetPointerShape->Height, pSetPointerShape->Width, pSetPointerShape->XHot, pSetPointerShape->YHot, pSetPointerShape->VidPnSourceId)); + return STATUS_NOT_SUPPORTED; } NTSTATUS QxlDod::Escape(_In_ CONST DXGKARG_ESCAPE* pEscape) @@ -330,13 +413,61 @@ NTSTATUS QxlDod::Escape(_In_ CONST DXGKARG_ESCAPE* pEscape) NTSTATUS QxlDod::PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly) { PAGED_CODE(); - + NTSTATUS Status = STATUS_SUCCESS; DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); QXL_ASSERT(pPresentDisplayOnly != NULL); QXL_ASSERT(pPresentDisplayOnly->VidPnSourceId < MAX_VIEWS); + if (pPresentDisplayOnly->BytesPerPixel < 4) + { + // Only >=32bpp modes are reported, therefore this Present should never pass anything less than 4 bytes per pixel + DbgPrint(TRACE_LEVEL_ERROR, ("pPresentDisplayOnly->BytesPerPixel is 0x%d, which is lower than the allowed.\n", 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; + } + + 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; + } + Status = ExecutePresentDisplayOnly( + pDst, + DstBitPerPixel, + (BYTE*)pPresentDisplayOnly->pSource, + pPresentDisplayOnly->BytesPerPixel, + pPresentDisplayOnly->Pitch, + pPresentDisplayOnly->NumMoves, + pPresentDisplayOnly->pMoves, + pPresentDisplayOnly->NumDirtyRects, + pPresentDisplayOnly->pDirtyRect, + RotationNeededByFb); + } DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); - return STATUS_SUCCESS; + return Status; } NTSTATUS QxlDod::QueryInterface(_In_ CONST PQUERY_INTERFACE pQueryInterface) @@ -356,11 +487,73 @@ NTSTATUS QxlDod::StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRE UNREFERENCED_PARAMETER(pDisplayInfo); QXL_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; - DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); return StopDevice(); } +VOID QxlDod::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(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 QxlDod::QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps) { PAGED_CODE(); @@ -466,25 +659,145 @@ NTSTATUS QxlDod::RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOG } NTSTATUS QxlDod::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + return AddSingleMonitorMode(pRecommendMonitorModes); +} + + +NTSTATUS QxlDod::AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface, + D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet, + D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + UNREFERENCED_PARAMETER(SourceId); + + // 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 (ULONG idx = 0; idx < m_ModeCount; ++idx) + { + // 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 + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%X, 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_ModeInfo[idx].XResolution; + pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = m_ModeInfo[idx].YResolution; + pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize; + pVidPnSourceModeInfo->Format.Graphics.Stride = m_ModeInfo[idx].BytesPerScanLine / m_ModeInfo[idx].XResolution; + pVidPnSourceModeInfo->Format.Graphics.PixelFormat = D3DDDIFMT_A8R8G8B8; + 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) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%X, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo)); + return Status; + } + } + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +// Add the current mode information (acquired from the POST frame buffer) as the target mode. +NTSTATUS QxlDod::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(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + UNREFERENCED_PARAMETER(pVidPnPinnedSourceModeInfo); + + D3DKMDT_VIDPN_TARGET_MODE* pVidPnTargetModeInfo = NULL; + NTSTATUS Status = STATUS_SUCCESS; + + for (UINT ModeIndex = 0; ModeIndex < m_ModeCount; ++ModeIndex) + { + pVidPnTargetModeInfo = NULL; + 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 + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet)); + return Status; + } + pVidPnTargetModeInfo->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER; + pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cx = m_ModeInfo[SourceId].XResolution; + pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cy = m_ModeInfo[SourceId].YResolution; + 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_NOTPREFERRED; // TODO: another logic for prefferred mode. Maybe the pinned source mode + + Status = pVidPnTargetModeSetInterface->pfnAddMode(hVidPnTargetModeSet, pVidPnTargetModeInfo); + if (!NT_SUCCESS(Status)) + { + if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnTargetModeInfo = 0x%I64x", Status, hVidPnTargetModeSet, pVidPnTargetModeInfo)); + } + + // 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 + Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnTargetModeInfo); + NT_ASSERT(NT_SUCCESS(Status)); + } + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + + +NTSTATUS QxlDod::AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) { PAGED_CODE(); NTSTATUS Status = STATUS_SUCCESS; D3DKMDT_MONITOR_SOURCE_MODE* pMonitorSourceMode = NULL; PVBE_MODEINFO pVbeModeInfo = NULL; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); 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 - DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet)); + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%X, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet)); return Status; } pVbeModeInfo = &m_ModeInfo[m_CurrentMode]; + + // 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 = pVbeModeInfo->XResolution;//m_CurrentModes[CorrespondingSourceId].DispInfo.Width; - pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = pVbeModeInfo->YResolution;//m_CurrentModes[CorrespondingSourceId].DispInfo.Height; + pMonitorSourceMode->VideoSignalInfo.TotalSize.cx = pVbeModeInfo->XResolution; + pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = pVbeModeInfo->YResolution; pMonitorSourceMode->VideoSignalInfo.ActiveSize = pMonitorSourceMode->VideoSignalInfo.TotalSize; pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; @@ -507,7 +820,7 @@ NTSTATUS QxlDod::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* { if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) { - DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x", + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%X, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode)); } else @@ -522,7 +835,62 @@ NTSTATUS QxlDod::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* return Status; } // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up - return STATUS_SUCCESS; + for (UINT Idx = 0; Idx < m_ModeCount; ++Idx) + { + // 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 + + pVbeModeInfo = &m_ModeInfo[Idx]; + // TODO: add routine for filling Monitor modepMonitorSourceMode = NULL; + 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 + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet)); + return Status; + } + + + DbgPrint(TRACE_LEVEL_INFORMATION, ("%s: add pref mode, dimensions %ux%u, taken from DxgkCbAcquirePostDisplayOwnership at StartDevice\n", __FUNCTION__, + pVbeModeInfo->XResolution, pVbeModeInfo->YResolution)); + + // 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 = pVbeModeInfo->XResolution; + pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = pVbeModeInfo->YResolution; + 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; //??? + + pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER; // ???? + pMonitorSourceMode->Preference = D3DKMDT_MP_NOTPREFERRED; // TODO... + 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) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x", + Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode)); + } + + // 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 + Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); + NT_ASSERT(NT_SUCCESS(Status)); + } + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; } // Tell DMM about all the modes, etc. that are supported @@ -531,7 +899,7 @@ NTSTATUS QxlDod::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODAL PAGED_CODE(); QXL_ASSERT(pEnumCofuncModality != NULL); - DbgPrint(TRACE_LEVEL_FATAL, ("---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0; D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0; @@ -572,10 +940,261 @@ NTSTATUS QxlDod::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODAL // 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x", + Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId)); + break; + } -//FIXME - - pVidPnPresentPathTemp = NULL; // Successfully released it + // 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePinnedModeInfo failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseSourceModeSet failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewSourceModeSet failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("AddSingleSourceMode failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn)); + break; + } + + // Give DMM back the source modes just populated + Status = pVidPnInterface->pfnAssignSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAssignSourceModeSet failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x", + Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId)); + break; + } + + Status = pVidPnTargetModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnTargetModeSet, &pVidPnPinnedTargetModeInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePinnedModeInfo failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseTargetModeSet failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x", + Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId)); + break; + } + + Status = AddSingleTargetMode(pVidPnTargetModeSetInterface, hVidPnTargetModeSet, pVidPnPinnedSourceModeInfo, pVidPnPresentPath->VidPnSourceId); + + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("AddSingleTargetMode failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn)); + break; + } + + // Give DMM back the source modes just populated + Status = pVidPnInterface->pfnAssignTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAssignTargetModeSet failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseModeInfo failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseTargetModeSet failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseModeInfo failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseSourceModeSet failed with Status = 0x%X, 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; + 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnUpdatePathSupportInfo failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireNextPathInfo failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleasePathInfo failed with Status = 0x%X, 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 @@ -629,14 +1248,14 @@ NTSTATUS QxlDod::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODAL QXL_ASSERT_CHK(TempStatus == STATUS_NOT_FOUND || Status != STATUS_SUCCESS); - DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); return Status; } NTSTATUS QxlDod::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility) { PAGED_CODE(); - DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); +// DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); QXL_ASSERT(pSetVidPnSourceVisibility != NULL); QXL_ASSERT((pSetVidPnSourceVisibility->VidPnSourceId < MAX_VIEWS) || (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL)); @@ -648,18 +1267,18 @@ NTSTATUS QxlDod::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIB { if (pSetVidPnSourceVisibility->Visible) { -// m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE; + m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE; } else { -// BlackOutScreen(SourceId); + BlackOutScreen(SourceId); } // Store current visibility so it can be dealt with during Present call -// m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible); + m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible); } - DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +// DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); return STATUS_SUCCESS; } @@ -672,21 +1291,339 @@ NTSTATUS QxlDod::CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn) QXL_ASSERT(pCommitVidPn != NULL); QXL_ASSERT(pCommitVidPn->AffectedVidPnSourceId < MAX_VIEWS); - NTSTATUS Status = STATUS_SUCCESS; + 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; + } -//FIXME + // 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbQueryVidPnInterface failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetTopology failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetNumPaths failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireSourceModeSet failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePinnedModeInfo failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetNumPathsFromSource failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnEnumPathTargetsFromSource failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePathInfo failed with Status = 0x%X, 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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleasePathInfo failed with Status = 0x%X, hVidPnTopoogy = 0x%I64x, pVidPnPresentPath = 0x%I64x", + Status, hVidPnTopology, pVidPnPresentPath)); + goto CommitVidPnExit; + } + pVidPnPresentPath = NULL; // Successfully released it + } + +CommitVidPnExit: + + NTSTATUS TempStatus; + UNREFERENCED_PARAMETER(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)); + } DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); return Status; } +NTSTATUS QxlDod::SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode, + CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + NTSTATUS Status = STATUS_SUCCESS; + + CURRENT_BDD_MODE* pCurrentBddMode = &m_CurrentModes[pPath->VidPnSourceId]; + + pCurrentBddMode->Scaling = pPath->ContentTransformation.Scaling; + pCurrentBddMode->SrcModeWidth = pSourceMode->Format.Graphics.VisibleRegionSize.cx; + pCurrentBddMode->SrcModeHeight = pSourceMode->Format.Graphics.VisibleRegionSize.cy; + pCurrentBddMode->Rotation = pPath->ContentTransformation.Rotation; + + pCurrentBddMode->DispInfo.Width = pSourceMode->Format.Graphics.PrimSurfSize.cx; + pCurrentBddMode->DispInfo.Height = pSourceMode->Format.Graphics.PrimSurfSize.cy; + pCurrentBddMode->DispInfo.Pitch = pSourceMode->Format.Graphics.PrimSurfSize.cx * BPPFromPixelFormat(pCurrentBddMode->DispInfo.ColorFormat) / BITS_PER_BYTE; + + + if (!pCurrentBddMode->Flags.DoNotMapOrUnmap) + { + // Map the new frame buffer + QXL_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; + for (USHORT ModeIndex = 0; ModeIndex < m_ModeCount; ++ModeIndex) + { + if (pCurrentBddMode->DispInfo.Width == m_ModeInfo[ModeIndex].XResolution && + pCurrentBddMode->DispInfo.Height == m_ModeInfo[ModeIndex].YResolution ) + { + Status = VbeSetCurrentMode(m_ModeNumbers[ModeIndex]); + if (NT_SUCCESS(Status)) + { + m_CurrentMode = ModeIndex; + } + break; + } + } + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS QxlDod::IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + if (pPath->VidPnSourceId >= MAX_VIEWS) + { + DbgPrint(TRACE_LEVEL_ERROR, ("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) + { + DbgPrint(TRACE_LEVEL_ERROR, ("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) + { + DbgPrint(TRACE_LEVEL_ERROR, ("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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pPath has a non-linear RGB color basis (0x%I64x)", pPath->VidPnTargetColorBasis)); + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + + +NTSTATUS QxlDod::IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + if (pSourceMode->Type != D3DKMDT_RMT_GRAPHICS) + { + DbgPrint(TRACE_LEVEL_ERROR, ("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)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("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) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode has a palettized access mode (0x%I64x)", pSourceMode->Format.Graphics.PixelValueAccessMode)); + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; + } + else + { + if (pSourceMode->Format.Graphics.PixelFormat == D3DDDIFMT_A8R8G8B8) + { + return STATUS_SUCCESS; + } + } + DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode has an unknown pixel format (0x%I64x)", pSourceMode->Format.Graphics.PixelFormat)); + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; +} + NTSTATUS QxlDod::UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath) { PAGED_CODE(); DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); QXL_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; DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); return STATUS_SUCCESS; @@ -729,11 +1666,51 @@ NTSTATUS QxlDod::SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID Target _Out_ D3DDDIFORMAT* pColorFormat) { UNREFERENCED_PARAMETER(Flags); - UNREFERENCED_PARAMETER(pColorFormat); - UNREFERENCED_PARAMETER(pWidth); - UNREFERENCED_PARAMETER(pHeight); + + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + m_SystemDisplaySourceId = D3DDDI_ID_UNINITIALIZED; + QXL_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; } @@ -754,12 +1731,38 @@ VOID QxlDod::SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VO 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 - - NTSTATUS QxlDod::WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue) { PAGED_CODE(); @@ -868,18 +1871,496 @@ NTSTATUS QxlDod::RegisterHWInfo() return Status; } + +NTSTATUS +QxlDod::ExecutePresentDisplayOnly( + _In_ BYTE* DstAddr, + _In_ UINT DstBitPerPixel, + _In_ BYTE* SrcAddr, + _In_ UINT SrcBytesPerPixel, + _In_ LONG SrcPitch, + _In_ ULONG NumMoves, + _In_ D3DKMT_MOVE_RECT* Moves, + _In_ ULONG NumDirtyRects, + _In_ RECT* DirtyRect, + _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation) +/*++ + + Routine Description: + + The method creates present worker thread and provides context + for it filled with present commands + + Arguments: + + DstAddr - address of destination surface + DstBitPerPixel - color depth of destination surface + SrcAddr - address of source surface + SrcBytesPerPixel - bytes per pixel of source surface + SrcPitch - source surface pitch (bytes in a row) + NumMoves - number of moves to be copied + Moves - moves' data + NumDirtyRects - number of rectangles to be copied + DirtyRect - rectangles' data + Rotation - roatation to be performed when executing copy + CallBack - callback for present worker thread to report execution status + + Return Value: + + Status + +--*/ +{ + + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + NTSTATUS Status = STATUS_SUCCESS; + + SIZE_T sizeMoves = NumMoves*sizeof(D3DKMT_MOVE_RECT); + SIZE_T sizeRects = NumDirtyRects*sizeof(RECT); + SIZE_T size = sizeof(DoPresentMemory) + sizeMoves + sizeRects; + + DoPresentMemory* ctx = reinterpret_cast + (new (NonPagedPoolNx) BYTE[size]); + + if (!ctx) + { + return STATUS_NO_MEMORY; + } + + RtlZeroMemory(ctx,size); + +// const CURRENT_BDD_MODE* pModeCur = GetCurrentMode(m_SourceId); + const CURRENT_BDD_MODE* pModeCur = &m_CurrentModes[0]; + ctx->DstAddr = DstAddr; + ctx->DstBitPerPixel = DstBitPerPixel; + ctx->DstStride = pModeCur->DispInfo.Pitch; //m_ModeInfo[m_CurrentMode].BytesPerScanLine;// + ctx->SrcWidth = pModeCur->SrcModeWidth;//m_ModeInfo[m_CurrentMode].XResolution;// + ctx->SrcHeight = pModeCur->SrcModeHeight;//m_ModeInfo[m_CurrentMode].YResolution;// + ctx->SrcAddr = NULL; + ctx->SrcPitch = SrcPitch; + ctx->Rotation = Rotation; + ctx->NumMoves = NumMoves; + ctx->Moves = Moves; + ctx->NumDirtyRects = NumDirtyRects; + ctx->DirtyRect = DirtyRect; +// ctx->SourceID = m_SourceId; +// ctx->hAdapter = m_DevExt; + ctx->Mdl = NULL; + ctx->DisplaySource = this; + + // Alternate between synch and asynch execution, for demonstrating + // that a real hardware implementation can do either + + { + // Map Source into kernel space, as Blt will be executed by system worker thread + UINT sizeToMap = SrcBytesPerPixel * ctx->SrcWidth * ctx->SrcHeight; + + PMDL mdl = IoAllocateMdl((PVOID)SrcAddr, sizeToMap, FALSE, FALSE, NULL); + if(!mdl) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + KPROCESSOR_MODE AccessMode = static_cast(( SrcAddr <= + (BYTE* const) MM_USER_PROBE_ADDRESS)?UserMode:KernelMode); + __try + { + // Probe and lock the pages of this buffer in physical memory. + // We need only IoReadAccess. + MmProbeAndLockPages(mdl, AccessMode, IoReadAccess); + } + #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here"); + __except(EXCEPTION_EXECUTE_HANDLER) + { + Status = GetExceptionCode(); + IoFreeMdl(mdl); + return Status; + } + + // Map the physical pages described by the MDL into system space. + // Note: double mapping the buffer this way causes lot of system + // overhead for large size buffers. + ctx->SrcAddr = reinterpret_cast + (MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority )); + + if(!ctx->SrcAddr) { + Status = STATUS_INSUFFICIENT_RESOURCES; + MmUnlockPages(mdl); + IoFreeMdl(mdl); + return Status; + } + + // Save Mdl to unmap and unlock the pages in worker thread + ctx->Mdl = mdl; + } + + BYTE* rects = reinterpret_cast(ctx+1); + + // copy moves and update pointer + if (Moves) + { + memcpy(rects,Moves,sizeMoves); + ctx->Moves = reinterpret_cast(rects); + rects += sizeMoves; + } + + // copy dirty rects and update pointer + if (DirtyRect) + { + memcpy(rects,DirtyRect,sizeRects); + ctx->DirtyRect = reinterpret_cast(rects); + } + + +// HwExecutePresentDisplayOnly((PVOID)ctx); + + + // Set up destination blt info + BLT_INFO DstBltInfo; + DstBltInfo.pBits = ctx->DstAddr; + DstBltInfo.Pitch = ctx->DstStride; + DstBltInfo.BitsPerPel = ctx->DstBitPerPixel; + DstBltInfo.Offset.x = 0; + DstBltInfo.Offset.y = 0; + DstBltInfo.Rotation = ctx->Rotation; + DstBltInfo.Width = ctx->SrcWidth; + DstBltInfo.Height = ctx->SrcHeight; + + // Set up source blt info + BLT_INFO SrcBltInfo; + SrcBltInfo.pBits = ctx->SrcAddr; + SrcBltInfo.Pitch = ctx->SrcPitch; + SrcBltInfo.BitsPerPel = 32; + SrcBltInfo.Offset.x = 0; + SrcBltInfo.Offset.y = 0; + SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY; + if (ctx->Rotation == D3DKMDT_VPPR_ROTATE90 || + ctx->Rotation == D3DKMDT_VPPR_ROTATE270) + { + SrcBltInfo.Width = DstBltInfo.Height; + SrcBltInfo.Height = DstBltInfo.Width; + } + else + { + SrcBltInfo.Width = DstBltInfo.Width; + SrcBltInfo.Height = DstBltInfo.Height; + } + + + // Copy all the scroll rects from source image to video frame buffer. + for (UINT i = 0; i < ctx->NumMoves; i++) + { + BltBits(&DstBltInfo, + &SrcBltInfo, + 1, // NumRects + &ctx->Moves[i].DestRect); + } + + // Copy all the dirty rects from source image to video frame buffer. + for (UINT i = 0; i < ctx->NumDirtyRects; i++) + { + + BltBits(&DstBltInfo, + &SrcBltInfo, + 1, // NumRects + &ctx->DirtyRect[i]); + } + + // Unmap unmap and unlock the pages. + if (ctx->Mdl) + { + MmUnlockPages(ctx->Mdl); + IoFreeMdl(ctx->Mdl); + } + delete [] reinterpret_cast(ctx); + + return STATUS_SUCCESS; +} + + +VOID QxlDod::GetPitches(_In_ CONST BLT_INFO* pBltInfo, _Out_ LONG* pPixelPitch, _Out_ LONG* pRowPitch) +{ + switch (pBltInfo->Rotation) + { + case D3DKMDT_VPPR_IDENTITY: + { + *pPixelPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE); + *pRowPitch = pBltInfo->Pitch; + return; + } + case D3DKMDT_VPPR_ROTATE90: + { + *pPixelPitch = -((LONG)pBltInfo->Pitch); + *pRowPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE); + return; + } + case D3DKMDT_VPPR_ROTATE180: + { + *pPixelPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE); + *pRowPitch = -((LONG)pBltInfo->Pitch); + return; + } + case D3DKMDT_VPPR_ROTATE270: + { + *pPixelPitch = pBltInfo->Pitch; + *pRowPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE); + return; + } + default: + { + QXL_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation); + *pPixelPitch = 0; + *pRowPitch = 0; + return; + } + } +} + +BYTE* QxlDod::GetRowStart(_In_ CONST BLT_INFO* pBltInfo, CONST RECT* pRect) +{ + BYTE* pRet = NULL; + LONG OffLeft = pRect->left + pBltInfo->Offset.x; + LONG OffTop = pRect->top + pBltInfo->Offset.y; + LONG BytesPerPixel = (pBltInfo->BitsPerPel / BITS_PER_BYTE); + switch (pBltInfo->Rotation) + { + case D3DKMDT_VPPR_IDENTITY: + { + pRet = ((BYTE*)pBltInfo->pBits + + OffTop * pBltInfo->Pitch + + OffLeft * BytesPerPixel); + break; + } + case D3DKMDT_VPPR_ROTATE90: + { + pRet = ((BYTE*)pBltInfo->pBits + + (pBltInfo->Height - 1 - OffLeft) * pBltInfo->Pitch + + OffTop * BytesPerPixel); + break; + } + case D3DKMDT_VPPR_ROTATE180: + { + pRet = ((BYTE*)pBltInfo->pBits + + (pBltInfo->Height - 1 - OffTop) * pBltInfo->Pitch + + (pBltInfo->Width - 1 - OffLeft) * BytesPerPixel); + break; + } + case D3DKMDT_VPPR_ROTATE270: + { + pRet = ((BYTE*)pBltInfo->pBits + + OffLeft * pBltInfo->Pitch + + (pBltInfo->Width - 1 - OffTop) * BytesPerPixel); + break; + } + default: + { + QXL_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation); + break; + } + } + + return pRet; +} + +/****************************Internal*Routine******************************\ + * CopyBitsGeneric + * + * + * Blt function which can handle a rotated dst/src, offset rects in dst/src + * and bpp combinations of: + * dst | src + * 32 | 32 // For identity rotation this is much faster in CopyBits32_32 + * 32 | 24 + * 32 | 16 + * 24 | 32 + * 16 | 32 + * 8 | 32 + * 24 | 24 // untested + * +\**************************************************************************/ + +VOID QxlDod::CopyBitsGeneric( + BLT_INFO* pDst, + CONST BLT_INFO* pSrc, + UINT NumRects, + _In_reads_(NumRects) CONST RECT *pRects) +{ + LONG DstPixelPitch = 0; + LONG DstRowPitch = 0; + LONG SrcPixelPitch = 0; + LONG SrcRowPitch = 0; + + DbgPrint(TRACE_LEVEL_VERBOSE , ("---> %s NumRects = %d Dst = %p Src = %p\n", __FUNCTION__, NumRects, pDst->pBits, pSrc->pBits)); + + GetPitches(pDst, &DstPixelPitch, &DstRowPitch); + GetPitches(pSrc, &SrcPixelPitch, &SrcRowPitch); + + for (UINT iRect = 0; iRect < NumRects; iRect++) + { + CONST RECT* pRect = &pRects[iRect]; + + NT_ASSERT(pRect->right >= pRect->left); + NT_ASSERT(pRect->bottom >= pRect->top); + + UINT NumPixels = pRect->right - pRect->left; + UINT NumRows = pRect->bottom - pRect->top; + + BYTE* pDstRow = GetRowStart(pDst, pRect); + CONST BYTE* pSrcRow = GetRowStart(pSrc, pRect); + + for (UINT y=0; y < NumRows; y++) + { + BYTE* pDstPixel = pDstRow; + CONST BYTE* pSrcPixel = pSrcRow; + + for (UINT x=0; x < NumPixels; x++) + { + if ((pDst->BitsPerPel == 24) || + (pSrc->BitsPerPel == 24)) + { + pDstPixel[0] = pSrcPixel[0]; + pDstPixel[1] = pSrcPixel[1]; + pDstPixel[2] = pSrcPixel[2]; + // pPixel[3] is the alpha channel and is ignored for whichever of Src/Dst is 32bpp + } + else if (pDst->BitsPerPel == 32) + { + if (pSrc->BitsPerPel == 32) + { + UINT32* pDstPixelAs32 = (UINT32*)pDstPixel; + UINT32* pSrcPixelAs32 = (UINT32*)pSrcPixel; + *pDstPixelAs32 = *pSrcPixelAs32; + } + else if (pSrc->BitsPerPel == 16) + { + UINT32* pDstPixelAs32 = (UINT32*)pDstPixel; + UINT16* pSrcPixelAs16 = (UINT16*)pSrcPixel; + + *pDstPixelAs32 = CONVERT_16BPP_TO_32BPP(*pSrcPixelAs16); + } + else + { + // Invalid pSrc->BitsPerPel on a pDst->BitsPerPel of 32 + NT_ASSERT(FALSE); + } + } + else if (pDst->BitsPerPel == 16) + { + NT_ASSERT(pSrc->BitsPerPel == 32); + + UINT16* pDstPixelAs16 = (UINT16*)pDstPixel; + *pDstPixelAs16 = CONVERT_32BPP_TO_16BPP(pSrcPixel); + } + else if (pDst->BitsPerPel == 8) + { + NT_ASSERT(pSrc->BitsPerPel == 32); + + *pDstPixel = CONVERT_32BPP_TO_8BPP(pSrcPixel); + } + else + { + // Invalid pDst->BitsPerPel + NT_ASSERT(FALSE); + } + pDstPixel += DstPixelPitch; + pSrcPixel += SrcPixelPitch; + } + + pDstRow += DstRowPitch; + pSrcRow += SrcRowPitch; + } + } +} + + +VOID QxlDod::CopyBits32_32( + BLT_INFO* pDst, + CONST BLT_INFO* pSrc, + UINT NumRects, + _In_reads_(NumRects) CONST RECT *pRects) +{ + NT_ASSERT((pDst->BitsPerPel == 32) && + (pSrc->BitsPerPel == 32)); + NT_ASSERT((pDst->Rotation == D3DKMDT_VPPR_IDENTITY) && + (pSrc->Rotation == D3DKMDT_VPPR_IDENTITY)); + + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + + for (UINT iRect = 0; iRect < NumRects; iRect++) + { + CONST RECT* pRect = &pRects[iRect]; + + NT_ASSERT(pRect->right >= pRect->left); + NT_ASSERT(pRect->bottom >= pRect->top); + + UINT NumPixels = pRect->right - pRect->left; + UINT NumRows = pRect->bottom - pRect->top; + UINT BytesToCopy = NumPixels * 4; + BYTE* pStartDst = ((BYTE*)pDst->pBits + + (pRect->top + pDst->Offset.y) * pDst->Pitch + + (pRect->left + pDst->Offset.x) * 4); + CONST BYTE* pStartSrc = ((BYTE*)pSrc->pBits + + (pRect->top + pSrc->Offset.y) * pSrc->Pitch + + (pRect->left + pSrc->Offset.x) * 4); + + for (UINT i = 0; i < NumRows; ++i) + { + RtlCopyMemory(pStartDst, pStartSrc, BytesToCopy); + pStartDst += pDst->Pitch; + pStartSrc += pSrc->Pitch; + } + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + +VOID QxlDod::BltBits ( + BLT_INFO* pDst, + CONST BLT_INFO* pSrc, + UINT NumRects, + _In_reads_(NumRects) CONST RECT *pRects) +{ + // pSrc->pBits might be coming from user-mode. User-mode addresses when accessed by kernel need to be protected by a __try/__except. + // This usage is redundant in the sample driver since it is already being used for MmProbeAndLockPages. However, it is very important + // to have this in place and to make sure developers don't miss it, it is in these two locations. + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + __try + { + if (pDst->BitsPerPel == 32 && + pSrc->BitsPerPel == 32 && + pDst->Rotation == D3DKMDT_VPPR_IDENTITY && + pSrc->Rotation == D3DKMDT_VPPR_IDENTITY) + { + // This is by far the most common copy function being called + CopyBits32_32(pDst, pSrc, NumRects, pRects); + } + else + { + CopyBitsGeneric(pDst, pSrc, NumRects, pRects); + } + } + #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here"); + __except(EXCEPTION_EXECUTE_HANDLER) + { + DbgPrint(TRACE_LEVEL_ERROR, ("Either dst (0x%I64x) or src (0x%I64x) bits encountered exception during access.\n", pDst->pBits, pSrc->pBits)); + } +} + + NTSTATUS QxlDod::VbeGetModeList() { PAGED_CODE(); USHORT m_Segment; USHORT m_Offset; - USHORT ModeCount; - ULONG SuitableModeCount; - USHORT ModeTemp; - USHORT CurrentMode; - PVBE_MODEINFO VbeModeInfo; + USHORT ModeCount; + ULONG SuitableModeCount; + USHORT ModeTemp; + USHORT CurrentMode; + PVBE_MODEINFO VbeModeInfo; VBE_INFO VbeInfo = {0}; - ULONG Length; + ULONG Length; NTSTATUS Status = STATUS_SUCCESS; DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); @@ -920,99 +2401,103 @@ NTSTATUS QxlDod::VbeGetModeList() if (!RtlEqualMemory(VbeInfo.Signature, "VESA", 4)) { - DbgPrint(TRACE_LEVEL_ERROR, ("No VBE BIOS present\n")); - return STATUS_UNSUCCESSFUL; - } + DbgPrint(TRACE_LEVEL_ERROR, ("No VBE BIOS present\n")); + return STATUS_UNSUCCESSFUL; + } DbgPrint(TRACE_LEVEL_ERROR, ("VBE BIOS Present (%d.%d, %8ld Kb)\n", VbeInfo.Version / 0x100, VbeInfo.Version & 0xFF, VbeInfo.TotalMemory * 64)); DbgPrint(TRACE_LEVEL_ERROR, ("Capabilities = 0x%x\n", VbeInfo.Capabilities)); DbgPrint(TRACE_LEVEL_ERROR, ("VideoModePtr = 0x%x (0x%x.0x%x)\n", VbeInfo.VideoModePtr, HIWORD( VbeInfo.VideoModePtr), LOWORD( VbeInfo.VideoModePtr))); - for (ModeCount = 0; ; ModeCount++) - { - /* Read the VBE mode number. */ - Status = x86BiosReadMemory ( - HIWORD(VbeInfo.VideoModePtr), - LOWORD(VbeInfo.VideoModePtr) + (ModeCount << 1), - &ModeTemp, - sizeof(ModeTemp)); - + for (ModeCount = 0; ; ModeCount++) + { + /* Read the VBE mode number. */ + Status = x86BiosReadMemory ( + HIWORD(VbeInfo.VideoModePtr), + LOWORD(VbeInfo.VideoModePtr) + (ModeCount << 1), + &ModeTemp, + sizeof(ModeTemp)); + if (!NT_SUCCESS (Status)) { DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosReadMemory failed with Status: 0x%X\n", Status)); break; } - /* End of list? */ - if (ModeTemp == 0xFFFF || ModeTemp == 0) - { - break; - } - } + /* End of list? */ + if (ModeTemp == 0xFFFF || ModeTemp == 0) + { + break; + } + } DbgPrint(TRACE_LEVEL_ERROR, ("ModeCount %d\n", ModeCount)); - m_ModeInfo = reinterpret_cast (new (PagedPool) BYTE[sizeof (VBE_MODEINFO) * ModeCount]); + m_ModeInfo = reinterpret_cast (new (PagedPool) BYTE[sizeof (VBE_MODEINFO) * ModeCount]); m_ModeNumbers = reinterpret_cast (new (PagedPool) BYTE [sizeof (USHORT) * ModeCount]); m_CurrentMode = 0; DbgPrint(TRACE_LEVEL_ERROR, ("m_ModeInfo = 0x%p, m_ModeNumbers = 0x%p\n", m_ModeInfo, m_ModeNumbers)); - for (CurrentMode = 0, SuitableModeCount = 0; - CurrentMode < ModeCount; - CurrentMode++) - { - Status = x86BiosReadMemory ( - HIWORD(VbeInfo.VideoModePtr), - LOWORD(VbeInfo.VideoModePtr) + (CurrentMode << 1), - &ModeTemp, - sizeof(ModeTemp)); - + for (CurrentMode = 0, SuitableModeCount = 0; + CurrentMode < ModeCount; + CurrentMode++) + { + Status = x86BiosReadMemory ( + HIWORD(VbeInfo.VideoModePtr), + LOWORD(VbeInfo.VideoModePtr) + (CurrentMode << 1), + &ModeTemp, + sizeof(ModeTemp)); + if (!NT_SUCCESS (Status)) { DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosReadMemory failed with Status: 0x%X\n", Status)); break; } - + DbgPrint(TRACE_LEVEL_ERROR, ("ModeTemp = 0x%X\n", ModeTemp)); - RtlZeroMemory(®s, sizeof(regs)); - regs.Eax = 0x4F01; - regs.Ecx = ModeTemp; - regs.Edi = m_Offset + sizeof (VbeInfo); - regs.SegEs = m_Segment; + RtlZeroMemory(®s, sizeof(regs)); + regs.Eax = 0x4F01; + regs.Ecx = ModeTemp; + regs.Edi = m_Offset + sizeof (VbeInfo); + regs.SegEs = m_Segment; if (!x86BiosCall (0x10, ®s)) { DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n")); return STATUS_UNSUCCESSFUL; } - Status = x86BiosReadMemory ( - m_Segment, - m_Offset + sizeof (VbeInfo), - m_ModeInfo + SuitableModeCount, - sizeof(VBE_MODEINFO)); - - VbeModeInfo = m_ModeInfo + SuitableModeCount; - - if (VbeModeInfo->XResolution >= 1024 && - VbeModeInfo->YResolution >= 768 && - VbeModeInfo->BitsPerPixel == 32 && - VbeModeInfo->PhysBasePtr != 0) - { - m_ModeNumbers[SuitableModeCount] = ModeTemp; - if (VbeModeInfo->XResolution == 1024 && - VbeModeInfo->YResolution == 768) - { - m_CurrentMode = (USHORT)SuitableModeCount; - } - SuitableModeCount++; - } - } - - if (SuitableModeCount == 0) - { + Status = x86BiosReadMemory ( + m_Segment, + m_Offset + sizeof (VbeInfo), + m_ModeInfo + SuitableModeCount, + sizeof(VBE_MODEINFO)); + + VbeModeInfo = m_ModeInfo + SuitableModeCount; + + if (VbeModeInfo->XResolution >= 1024 && + VbeModeInfo->YResolution >= 768 && + VbeModeInfo->BitsPerPixel == 24 && + VbeModeInfo->PhysBasePtr != 0) + { + m_ModeNumbers[SuitableModeCount] = ModeTemp; + if (VbeModeInfo->XResolution == 1024 && + VbeModeInfo->YResolution == 768) + { + m_CurrentMode = (USHORT)SuitableModeCount; + } + SuitableModeCount++; + } + } + + if (SuitableModeCount == 0) + { DbgPrint(TRACE_LEVEL_ERROR, ("No video modes supported\n")); Status = STATUS_UNSUCCESSFUL; - } - - m_ModeCount = SuitableModeCount; + } + + m_ModeCount = SuitableModeCount; DbgPrint(TRACE_LEVEL_ERROR, ("ModeCount filtered %d\n", m_ModeCount)); + for (ULONG idx = 0; idx < m_ModeCount; idx++) + { + DbgPrint(TRACE_LEVEL_ERROR, ("type %x, XRes = %d, YRes = %d, BPP = %d\n", m_ModeNumbers[idx], m_ModeInfo[idx].XResolution, m_ModeInfo[idx].YResolution, m_ModeInfo[idx].BitsPerPixel)); + } if (m_Segment != 0) { @@ -1026,49 +2511,161 @@ NTSTATUS QxlDod::VbeQueryCurrentMode(PVIDEO_MODE RequestedMode) { DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); NTSTATUS Status = STATUS_SUCCESS; - PVBE_MODEINFO VBEMode = &m_ModeInfo[m_CurrentMode]; + UNREFERENCED_PARAMETER(RequestedMode); +// PVBE_MODEINFO VBEMode = &m_ModeInfo[m_CurrentMode]; return Status; } -NTSTATUS QxlDod::VbeSetCurrentMode(PVIDEO_MODE RequestedMode) +NTSTATUS QxlDod::VbeSetCurrentMode(ULONG Mode) { NTSTATUS Status = STATUS_SUCCESS; - DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s Mode = %x\n", __FUNCTION__, Mode)); X86BIOS_REGISTERS regs = {0}; regs.Eax = 0x4F02; - regs.Edx = m_ModeNumbers[RequestedMode->RequestedMode]; + regs.Ebx = Mode | 0x000; if (!x86BiosCall (0x10, ®s)) { DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n")); return STATUS_UNSUCCESSFUL; } - m_CurrentMode = (USHORT)RequestedMode->RequestedMode; DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); return Status; } +NTSTATUS QxlDod::VbeGetCurrentMode(ULONG* pMode) +{ + NTSTATUS Status = STATUS_SUCCESS; + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + X86BIOS_REGISTERS regs = {0}; + regs.Eax = 0x4F03; + if (!x86BiosCall (0x10, ®s)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n")); + return STATUS_UNSUCCESSFUL; + } + *pMode = regs.Ebx; + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> EAX = %x, EBX = %x Mode = %x\n", regs.Eax, regs.Ebx, *pMode)); + return Status; +} + NTSTATUS QxlDod::VbeSetPowerState(POWER_ACTION ActionType) { - NTSTATUS Status = STATUS_SUCCESS; DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); X86BIOS_REGISTERS regs = {0}; regs.Eax = 0x4F10; regs.Ebx = 1; - switch (ActionType) - { - case PowerActionSleep: regs.Ebx |= 0x100; break; - case PowerActionHibernate: regs.Ebx |= 0x200; break; - case PowerActionShutdown: - case PowerActionShutdownReset: - case PowerActionShutdownOff: regs.Ebx |= 0x400; break; - } + switch (ActionType) + { + case PowerActionNone: break; + case PowerActionSleep: regs.Ebx |= 0x100; break; + case PowerActionHibernate: regs.Ebx |= 0x200; break; + case PowerActionShutdown: + case PowerActionShutdownReset: + case PowerActionShutdownOff: regs.Ebx |= 0x400; break; + } if (!x86BiosCall (0x10, ®s)) { DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n")); return STATUS_UNSUCCESSFUL; } DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); - return Status; + return STATUS_SUCCESS; } + +// +// Non-Paged Code +// +#pragma code_seg(push) +#pragma code_seg() +D3DDDI_VIDEO_PRESENT_SOURCE_ID QxlDod::FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero) +{ + UNREFERENCED_PARAMETER(TargetId); + for (UINT SourceId = 0; SourceId < MAX_VIEWS; ++SourceId) + { + if (m_CurrentModes[SourceId].FrameBuffer.Ptr != NULL) + { + return SourceId; + } + } + + return DefaultToZero ? 0 : D3DDDI_ID_UNINITIALIZED; +} + +#pragma code_seg(pop) // End Non-Paged Code + +// +// Frame buffer map/unmap +// + +NTSTATUS +MapFrameBuffer( + _In_ PHYSICAL_ADDRESS PhysicalAddress, + _In_ ULONG Length, + _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress) +{ + PAGED_CODE(); + + // + // Check for parameters + // + if ((PhysicalAddress.QuadPart == (ULONGLONG)0) || + (Length == 0) || + (VirtualAddress == NULL)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("One of PhysicalAddress.QuadPart (0x%I64x), Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0", + PhysicalAddress.QuadPart, Length, VirtualAddress)); + return STATUS_INVALID_PARAMETER; + } + + *VirtualAddress = MmMapIoSpace(PhysicalAddress, + Length, + MmWriteCombined); + if (*VirtualAddress == NULL) + { + // The underlying call to MmMapIoSpace failed. This may be because, MmWriteCombined + // isn't supported, so try again with MmNonCached + + *VirtualAddress = MmMapIoSpace(PhysicalAddress, + Length, + MmNonCached); + if (*VirtualAddress == NULL) + { + DbgPrint(TRACE_LEVEL_ERROR, ("MmMapIoSpace returned a NULL buffer when trying to allocate 0x%I64x bytes", Length)); + return STATUS_NO_MEMORY; + } + } + + return STATUS_SUCCESS; +} + +NTSTATUS +UnmapFrameBuffer( + _In_reads_bytes_(Length) VOID* VirtualAddress, + _In_ ULONG Length) +{ + PAGED_CODE(); + + + // + // Check for parameters + // + if ((VirtualAddress == NULL) && (Length == 0)) + { + // Allow this function to be called when there's no work to do, and treat as successful + return STATUS_SUCCESS; + } + else if ((VirtualAddress == NULL) || (Length == 0)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("Only one of Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0", + Length, VirtualAddress)); + return STATUS_INVALID_PARAMETER; + } + + MmUnmapIoSpace(VirtualAddress, + Length); + + return STATUS_SUCCESS; +} + diff --git a/qxldod/QxlDod.h b/qxldod/QxlDod.h index 18ec7b1..048aec8 100755 --- a/qxldod/QxlDod.h +++ b/qxldod/QxlDod.h @@ -1,17 +1,32 @@ #pragma once #include "baseobject.h" +#define MAX_CHILDREN 1 +#define MAX_VIEWS 1 +#define BITS_PER_BYTE 8 + typedef struct _QXL_FLAGS { UINT DriverStarted : 1; // ( 1) 1 after StartDevice and 0 after StopDevice UINT Unused : 31; } QXL_FLAGS; -#define MAX_CHILDREN 1 -#define MAX_VIEWS 1 +// For the following macros, c must be a UCHAR. +#define UPPER_6_BITS(c) (((c) & rMaskTable[6 - 1]) >> 2) +#define UPPER_5_BITS(c) (((c) & rMaskTable[5 - 1]) >> 3) +#define LOWER_6_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 6]) +#define LOWER_5_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 5]) -#pragma pack(push) -#pragma pack(1) + +#define SHIFT_FOR_UPPER_5_IN_565 (6 + 5) +#define SHIFT_FOR_MIDDLE_6_IN_565 (5) +#define SHIFT_UPPER_5_IN_565_BACK ((BITS_PER_BYTE * 2) + (BITS_PER_BYTE - 5)) +#define SHIFT_MIDDLE_6_IN_565_BACK ((BITS_PER_BYTE * 1) + (BITS_PER_BYTE - 6)) +#define SHIFT_LOWER_5_IN_565_BACK ((BITS_PER_BYTE * 0) + (BITS_PER_BYTE - 5)) + + +#pragma pack(push) +#pragma pack(1) typedef struct { @@ -83,7 +98,7 @@ typedef struct CHAR Reserved4[189]; } VBE_MODEINFO, *PVBE_MODEINFO; -#pragma pack(pop) +#pragma pack(pop) typedef struct _X86BIOS_REGISTERS // invented names { @@ -116,6 +131,79 @@ NTHALAPI NTSTATUS x86BiosWriteMemory (USHORT, USHORT, PVOID, ULONG); } #endif +struct DoPresentMemory +{ + PVOID DstAddr; + UINT DstStride; + ULONG DstBitPerPixel; + UINT SrcWidth; + UINT SrcHeight; + BYTE* SrcAddr; + LONG SrcPitch; + ULONG NumMoves; // in: Number of screen to screen moves + D3DKMT_MOVE_RECT* Moves; // in: Point to the list of moves + ULONG NumDirtyRects; // in: Number of direct rects + RECT* DirtyRect; // in: Point to the list of dirty rects + D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation; + D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceID; + HANDLE hAdapter; + PMDL Mdl; + PVOID DisplaySource; +}; + +typedef struct _BLT_INFO +{ + PVOID pBits; + UINT Pitch; + UINT BitsPerPel; + POINT Offset; // To unrotated top-left of dirty rects + D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation; + UINT Width; // For the unrotated image + UINT Height; // For the unrotated image +} BLT_INFO; + +// Represents the current mode, may not always be set (i.e. frame buffer mapped) if representing the mode passed in on single mode setups. +typedef struct _CURRENT_BDD_MODE +{ + // The source mode currently set for HW Framebuffer + // For sample driver this info filled in StartDevice by the OS and never changed. + DXGK_DISPLAY_INFORMATION DispInfo; + + // The rotation of the current mode. Rotation is performed in software during Present call + D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation; + + D3DKMDT_VIDPN_PRESENT_PATH_SCALING Scaling; + // This mode might be different from one which are supported for HW frame buffer + // Scaling/displasment might be needed (if supported) + UINT SrcModeWidth; + UINT SrcModeHeight; + + // Various boolean flags the struct uses + struct _CURRENT_BDD_MODE_FLAGS + { + UINT SourceNotVisible : 1; // 0 if source is visible + UINT FullscreenPresent : 1; // 0 if should use dirty rects for present + UINT FrameBufferIsActive : 1; // 0 if not currently active (i.e. target not connected to source) + UINT DoNotMapOrUnmap : 1; // 1 if the FrameBuffer should not be (un)mapped during normal execution + UINT IsInternal : 1; // 1 if it was determined (i.e. through ACPI) that an internal panel is being driven + UINT Unused : 27; + } Flags; + + // The start and end of physical memory known to be all zeroes. Used to optimize the BlackOutScreen function to not write + // zeroes to memory already known to be zero. (Physical address is located in DispInfo) + PHYSICAL_ADDRESS ZeroedOutStart; + PHYSICAL_ADDRESS ZeroedOutEnd; + + // Linear frame buffer pointer + // A union with a ULONG64 is used here to ensure this struct looks the same on 32bit and 64bit builds + // since the size of a VOID* changes depending on the build. + union + { + VOID* Ptr; + ULONG64 Force8Bytes; + } FrameBuffer; +} CURRENT_BDD_MODE; + class QxlDod : public BaseObject @@ -128,10 +216,13 @@ private: DEVICE_POWER_STATE m_MonitorPowerState; DEVICE_POWER_STATE m_AdapterPowerState; QXL_FLAGS m_Flags; - PVBE_MODEINFO m_ModeInfo; + PVBE_MODEINFO m_ModeInfo; ULONG m_ModeCount; PUSHORT m_ModeNumbers; USHORT m_CurrentMode; + CURRENT_BDD_MODE m_CurrentModes[MAX_VIEWS]; + D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SystemDisplaySourceId; + DXGKARG_SETPOINTERSHAPE m_PointerShape; public: QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject); ~QxlDod(void); @@ -219,18 +310,109 @@ public: // Must be Non-Paged // Write out pixels as part of bugcheck VOID SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource, - _In_ UINT SourceWidth, - _In_ UINT SourceHeight, - _In_ UINT SourceStride, - _In_ INT PositionX, - _In_ INT PositionY); + _In_ UINT SourceWidth, + _In_ UINT SourceHeight, + _In_ UINT SourceStride, + _In_ INT PositionX, + _In_ INT PositionY); private: VOID CleanUp(VOID); NTSTATUS WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue); + // Set the given source mode on the given path + NTSTATUS SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode, + CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath); + + // Add the current mode to the given monitor source mode set + NTSTATUS AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); + + // Add the current mode to the given VidPn source mode set + NTSTATUS AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface, + D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet, + D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); + + // Add the current mode (or the matching to pinned source mode) to the give VidPn target mode set + NTSTATUS AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface, + D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet, + _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo, + D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); + D3DDDI_VIDEO_PRESENT_SOURCE_ID FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero); + NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const; + NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const; + + NTSTATUS RegisterHWInfo(); NTSTATUS VbeGetModeList(); + + NTSTATUS ExecutePresentDisplayOnly(_In_ BYTE* DstAddr, + _In_ UINT DstBitPerPixel, + _In_ BYTE* SrcAddr, + _In_ UINT SrcBytesPerPixel, + _In_ LONG SrcPitch, + _In_ ULONG NumMoves, + _In_ D3DKMT_MOVE_RECT* pMoves, + _In_ ULONG NumDirtyRects, + _In_ RECT* pDirtyRect, + _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation); + BYTE* GetRowStart(_In_ CONST BLT_INFO* pBltInfo, CONST RECT* pRect); + VOID GetPitches(_In_ CONST BLT_INFO* pBltInfo, _Out_ LONG* pPixelPitch, _Out_ LONG* pRowPitch); + VOID CopyBitsGeneric( + BLT_INFO* pDst, + CONST BLT_INFO* pSrc, + UINT NumRects, + _In_reads_(NumRects) CONST RECT *pRects); + + VOID CopyBits32_32( + BLT_INFO* pDst, + CONST BLT_INFO* pSrc, + UINT NumRects, + _In_reads_(NumRects) CONST RECT *pRects); + VOID BltBits ( + BLT_INFO* pDst, + CONST BLT_INFO* pSrc, + UINT NumRects, + _In_reads_(NumRects) CONST RECT *pRects); + VOID BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); + NTSTATUS VbeQueryCurrentMode(PVIDEO_MODE RequestedMode); - NTSTATUS VbeSetCurrentMode(PVIDEO_MODE RequestedMode); + NTSTATUS VbeSetCurrentMode(ULONG Mode); + NTSTATUS VbeGetCurrentMode(ULONG* Mode); NTSTATUS VbeSetPowerState(POWER_ACTION ActionType); + UINT BPPFromPixelFormat(D3DDDIFORMAT Format) const + { + switch (Format) + { + case D3DDDIFMT_UNKNOWN: return 0; + case D3DDDIFMT_P8: return 8; + case D3DDDIFMT_R5G6B5: return 16; + case D3DDDIFMT_R8G8B8: return 24; + case D3DDDIFMT_X8R8G8B8: // fall through + case D3DDDIFMT_A8R8G8B8: return 32; + default: QXL_LOG_ASSERTION1("Unknown D3DDDIFORMAT 0x%I64x", Format); return 0; + } + } + + // Given bits per pixel, return the pixel format at the same bpp + D3DDDIFORMAT PixelFormatFromBPP(UINT BPP) const + { + switch (BPP) + { + case 8: return D3DDDIFMT_P8; + case 16: return D3DDDIFMT_R5G6B5; + case 24: return D3DDDIFMT_R8G8B8; + case 32: return D3DDDIFMT_X8R8G8B8; + default: QXL_LOG_ASSERTION1("A bit per pixel of 0x%I64x is not supported.", BPP); return D3DDDIFMT_UNKNOWN; + } + } }; +NTSTATUS +MapFrameBuffer( + _In_ PHYSICAL_ADDRESS PhysicalAddress, + _In_ ULONG Length, + _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress); + +NTSTATUS +UnmapFrameBuffer( + _In_reads_bytes_(Length) VOID* VirtualAddress, + _In_ ULONG Length); + diff --git a/qxldod/driver.cpp b/qxldod/driver.cpp index 546fc88..bdf4c04 100755 --- a/qxldod/driver.cpp +++ b/qxldod/driver.cpp @@ -9,7 +9,7 @@ // Driver Entry point // -int nDebugLevel = TRACE_LEVEL_VERBOSE; +int nDebugLevel = TRACE_LEVEL_INFORMATION; extern "C" @@ -93,7 +93,7 @@ DodAddDevice( _Outptr_ PVOID* ppDeviceContext) { PAGED_CODE(); - DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); if ((pPhysicalDeviceObject == NULL) || (ppDeviceContext == NULL)) @@ -113,7 +113,7 @@ DodAddDevice( *ppDeviceContext = pQxl; - DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); return STATUS_SUCCESS; } @@ -122,7 +122,7 @@ DodRemoveDevice( _In_ VOID* pDeviceContext) { PAGED_CODE(); - DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); @@ -132,7 +132,7 @@ DodRemoveDevice( pQxl = NULL; } - DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); return STATUS_SUCCESS; } @@ -146,7 +146,7 @@ DodStartDevice( { PAGED_CODE(); QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); return pQxl->StartDevice(pDxgkStartInfo, pDxgkInterface, pNumberOfViews, pNumberOfChildren); @@ -158,7 +158,7 @@ DodStopDevice( { PAGED_CODE(); QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); return pQxl->StopDevice(); @@ -173,7 +173,7 @@ DodDispatchIoRequest( { PAGED_CODE(); QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); if (!pQxl->IsDriverActive()) @@ -193,7 +193,7 @@ DodSetPowerState( { PAGED_CODE(); QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); if (!pQxl->IsDriverActive()) @@ -215,7 +215,7 @@ DodQueryChildRelations( { PAGED_CODE(); QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); return pQxl->QueryChildRelations(pChildRelations, ChildRelationsSize); @@ -229,7 +229,7 @@ DodQueryChildStatus( { PAGED_CODE(); QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); return pQxl->QueryChildStatus(pChildStatus, NonDestructiveOnly); @@ -243,7 +243,7 @@ DodQueryDeviceDescriptor( { PAGED_CODE(); QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); if (!pQxl->IsDriverActive()) @@ -271,7 +271,7 @@ DodQueryAdapterInfo( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); return pQxl->QueryAdapterInfo(pQueryAdapterInfo); @@ -285,7 +285,7 @@ DodSetPointerPosition( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -304,7 +304,7 @@ DodSetPointerShape( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -324,7 +324,7 @@ DodEscape( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); return pQxl->Escape(pEscape); @@ -338,7 +338,7 @@ DodQueryInterface( { PAGED_CODE(); QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); return pQxl->QueryInterface(QueryInterface); @@ -352,7 +352,7 @@ DodPresentDisplayOnly( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); -// DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -372,7 +372,7 @@ DodStopDeviceAndReleasePostDisplayOwnership( { PAGED_CODE(); QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); return pQxl->StopDeviceAndReleasePostDisplayOwnership(TargetId, DisplayInfo); @@ -386,7 +386,7 @@ DodIsSupportedVidPn( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -408,7 +408,7 @@ DodRecommendFunctionalVidPn( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -427,7 +427,7 @@ DodRecommendVidPnTopology( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -446,7 +446,7 @@ DodRecommendMonitorModes( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -465,7 +465,7 @@ DodEnumVidPnCofuncModality( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -484,7 +484,7 @@ DodSetVidPnSourceVisibility( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -503,7 +503,7 @@ DodCommitVidPn( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -522,7 +522,7 @@ DodUpdateActiveVidPnPresentPath( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -541,7 +541,7 @@ DodQueryVidPnHWCapability( { PAGED_CODE(); QXL_ASSERT_CHK(hAdapter != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(hAdapter); if (!pQxl->IsDriverActive()) @@ -564,7 +564,7 @@ DodDpcRoutine( _In_ VOID* pDeviceContext) { QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); if (!pQxl->IsDriverActive()) @@ -573,7 +573,7 @@ DodDpcRoutine( return; } pQxl->DpcRoutine(); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); } BOOLEAN @@ -582,7 +582,7 @@ DodInterruptRoutine( _In_ ULONG MessageNumber) { QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); return pQxl->InterruptRoutine(MessageNumber); @@ -593,7 +593,7 @@ DodResetDevice( _In_ VOID* pDeviceContext) { QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); pQxl->ResetDevice(); @@ -610,7 +610,7 @@ DodSystemDisplayEnable( _Out_ D3DDDIFORMAT* ColorFormat) { QXL_ASSERT_CHK(pDeviceContext != NULL); - DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); QxlDod* pQxl = reinterpret_cast(pDeviceContext); return pQxl->SystemDisplayEnable(TargetId, Flags, Width, Height, ColorFormat);