From f4243ef7ea8d2e691b473cb224ff66e14ac19c78 Mon Sep 17 00:00:00 2001 From: Sudharsan Raman Date: Tue, 2 Aug 2022 20:21:22 +0530 Subject: [PATCH] ZC v540 : Multi monitor support, logging and QEMU edid caching --- DVApp.ps1 | 9 +- DVInstaller.ps1 | 2 +- DVServerKMD/DVServerKMD.vcxproj | 1 + DVServerKMD/DVServerKMD_Version.txt | 2 +- DVServerKMD/Public.h | 20 +- DVServerKMD/Queue.cpp | 106 ++++- DVServerKMD/Queue.h | 7 + DVServerKMD/debug.h | 10 + DVServerKMD/edid.h | 2 +- DVServerKMD/helper.h | 1 - DVServerKMD/qemu_edid.h | 2 +- DVServerKMD/viogpu_queue.cpp | 60 ++- DVServerKMD/viogpu_queue.h | 4 +- DVServerKMD/viogpulite.cpp | 404 ++++++++++-------- DVServerKMD/viogpulite.h | 83 ++-- DVServerUMD/Common/debug.h | 11 + DVServerUMD/DVEnabler/DVEnabler/DVEnabler.cpp | 59 +-- .../DVEnabler/DVEnabler/DVEnabler.vcxproj | 2 +- DVServerUMD/DVServer/DVServer.vcxproj | 1 + DVServerUMD/DVServer/DVServerUMD_Version.txt | 2 +- DVServerUMD/DVServer/DVServercommon.h | 9 +- DVServerUMD/DVServer/DVServeredid.cpp | 182 ++++---- DVServerUMD/DVServer/DVServeredid.h | 6 +- DVServerUMD/DVServer/DVServerregistry.cpp | 160 +++++++ DVServerUMD/DVServer/Driver.cpp | 353 ++++++++------- DVServerUMD/DVServer/Driver.h | 24 +- DVServerUMD/DVServerUMD_Node/main.cpp | 2 +- EDIDParser/edidparser.c | 2 +- EDIDParser/edidparser.h | 2 +- EDIDParser/edidshared.h | 6 +- Readme.txt | 9 +- 31 files changed, 1003 insertions(+), 540 deletions(-) create mode 100644 DVServerUMD/DVServer/DVServerregistry.cpp diff --git a/DVApp.ps1 b/DVApp.ps1 index 8cead4d..6212ff6 100644 --- a/DVApp.ps1 +++ b/DVApp.ps1 @@ -1,7 +1,7 @@ #=========================================================================== #DVApp.ps1 #---------------------------------------------------------------------------- -#* Copyright © 2021 Intel Corporation +#Copyright (C) 2021 Intel Corporation #SPDX-License-Identifier: MIT #--------------------------------------------------------------------------*/ @@ -57,7 +57,12 @@ function create_node() Write-Host "Turning off MSFT Path" & ".\DVEnabler.exe" - return "SUCCESS" + if ($LASTEXITCODE -eq 0) { + return "SUCCESS" + } else { + Write-Host "DVEnabler failed. DVServerUMD has not taken over MSBDA!" + return "FAIL" + } } #This API will execute the setup/run commands diff --git a/DVInstaller.ps1 b/DVInstaller.ps1 index b335157..b2c35d5 100644 --- a/DVInstaller.ps1 +++ b/DVInstaller.ps1 @@ -1,7 +1,7 @@ #=========================================================================== #DVInstaller.ps1 #---------------------------------------------------------------------------- -#* Copyright © 2021 Intel Corporation +#Copyright (C) 2021 Intel Corporation #SPDX-License-Identifier: MIT #--------------------------------------------------------------------------*/ diff --git a/DVServerKMD/DVServerKMD.vcxproj b/DVServerKMD/DVServerKMD.vcxproj index be160bc..7e24efe 100644 --- a/DVServerKMD/DVServerKMD.vcxproj +++ b/DVServerKMD/DVServerKMD.vcxproj @@ -95,6 +95,7 @@ trace.h true C:\Program Files %28x86%29\Windows Kits\10\Include\10.0.19041.0\um;C:\Program Files %28x86%29\Windows Kits\10\Include\10.0.19041.0\km;..\VirtIO;..\EDIDParser;%(AdditionalIncludeDirectories) + _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions);__DEBUG virtiolib.lib;edidparser.lib;%(AdditionalDependencies) diff --git a/DVServerKMD/DVServerKMD_Version.txt b/DVServerKMD/DVServerKMD_Version.txt index 8a577e7..0a8d3ab 100644 --- a/DVServerKMD/DVServerKMD_Version.txt +++ b/DVServerKMD/DVServerKMD_Version.txt @@ -1,7 +1,7 @@ /*=========================================================================== ; DVServerKMD_Version.txt ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: BSD-3-Clause ; ; File Description: diff --git a/DVServerKMD/Public.h b/DVServerKMD/Public.h index c49bedc..afff390 100644 --- a/DVServerKMD/Public.h +++ b/DVServerKMD/Public.h @@ -24,12 +24,14 @@ DEFINE_GUID (GUID_DEVINTERFACE_DVServerKMD, 0x1c514918,0xa855,0x460a,0x97,0xda,0xed,0x69,0x1d,0xd5,0x63,0xcf); // {1c514918-a855-460a-97da-ed691dd563cf} -#define IOCTL_DVSERVER_FRAME_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DVSERVER_CURSOR_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DVSERVER_GET_EDID_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DVSERVER_SET_MODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DVSERVER_GENERAL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DVSERVER_TEST_IMAGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x812, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define MAX_SCAN_OUT 4 +#define IOCTL_DVSERVER_FRAME_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DVSERVER_CURSOR_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DVSERVER_GET_EDID_DATA CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DVSERVER_SET_MODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DVSERVER_GENERAL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DVSERVER_TEST_IMAGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x812, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DVSERVER_GET_TOTAL_SCREENS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x813, METHOD_BUFFERED, FILE_ANY_ACCESS) typedef struct FrameMetaData { @@ -41,6 +43,7 @@ typedef struct FrameMetaData UINT16 bitrate; void* addr; unsigned short refresh_rate; + unsigned int screen_num; }FrameMetaData; @@ -68,9 +71,14 @@ struct edid_info { unsigned char edid_data[256]; unsigned int mode_size; + unsigned int screen_num; mode_info* mode_list; }; +struct screen_info +{ + unsigned int total_screens; +}; struct KMDF_IOCTL_Response { diff --git a/DVServerKMD/Queue.cpp b/DVServerKMD/Queue.cpp index 8a7df63..56d6c3a 100644 --- a/DVServerKMD/Queue.cpp +++ b/DVServerKMD/Queue.cpp @@ -1,6 +1,6 @@ /*++ * -* Copyright © 2021 Intel Corporation +* Copyright (C) 2021 Intel Corporation * SPDX-License-Identifier: MS-PL Module Name: @@ -32,9 +32,6 @@ extern "C" { #pragma alloc_text (PAGE, DVServerKMDQueueInitialize) #endif -extern GPU_DISP_MODE_EXT gpu_disp_mode_ext[MAX_MODELIST_SIZE]; -extern output_modelist mode_list; - NTSTATUS DVServerKMDQueueInitialize( _In_ WDFDEVICE Device @@ -154,8 +151,10 @@ Return Value: // method retrieves an I/O request's input buffer. // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdfrequest/nf-wdfrequest-wdfrequestretrieveinputbuffer status = IoctlRequestPresentFb(pDeviceContext, InputBufferLength, OutputBufferLength, Request, &bytesReturned); - if (status != STATUS_SUCCESS) + if (status != STATUS_SUCCESS) { + ERR("IoctlRequestPresentFb failed with status = %d\n", status); return; + } status = WdfRequestRetrieveOutputBuffer(Request, 0, (PVOID*)&resp, &bufSize); if (!NT_SUCCESS(status)) { ERR("Couldn't retrieve Output buffer\n"); @@ -232,6 +231,11 @@ Return Value: resp->retval = DVSERVERKMD_SUCCESS; WdfRequestSetInformation(Request, sizeof(struct KMDF_IOCTL_Response)); break; + case IOCTL_DVSERVER_GET_TOTAL_SCREENS: + status = IoctlRequestTotalScreens(pDeviceContext, InputBufferLength, OutputBufferLength, Request, &bytesReturned); + if (status != STATUS_SUCCESS) + return; + break; } WdfRequestComplete(Request, STATUS_SUCCESS); @@ -341,29 +345,40 @@ static NTSTATUS IoctlRequestSetMode( return STATUS_INVALID_USER_BUFFER; } + if (ptr->screen_num >= MAX_SCAN_OUT) { + ERR("Screen number provided by UMD: %d is greater than or equal to the maximum supported: %d by the KMD\n", + ptr->screen_num, MAX_SCAN_OUT); + WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); + return status; + } + CURRENT_MODE tempCurrentMode = { 0 }; tempCurrentMode.DispInfo.Width = ptr->width; tempCurrentMode.DispInfo.Height = ptr->height; tempCurrentMode.DispInfo.Pitch = ptr->pitch; + tempCurrentMode.DispInfo.TargetId = ptr->screen_num; tempCurrentMode.DispInfo.ColorFormat = (D3DDDIFORMAT) ptr->format; tempCurrentMode.FrameBuffer.Ptr = (BYTE*)ptr->addr; status = pAdapter->SetCurrentModeExt(&tempCurrentMode); - if (status != STATUS_SUCCESS) + if (status != STATUS_SUCCESS) { + ERR("SetCurrentModeExt failed with status = %d\n", status); return STATUS_UNSUCCESSFUL; + } // BlackOutScreen CURRENT_MODE CurrentMode = { 0 }; CurrentMode.DispInfo.Width = ptr->width; CurrentMode.DispInfo.Height = ptr->height; CurrentMode.DispInfo.Pitch = ptr->pitch; - CurrentMode.FrameBuffer.Ptr = pAdapter->m_FrameSegment.GetFbVAddr(); + CurrentMode.DispInfo.TargetId = ptr->screen_num; + CurrentMode.FrameBuffer.Ptr = pAdapter->GetFbVAddr(ptr->screen_num); CurrentMode.Flags.FrameBufferIsActive = 1; pAdapter->BlackOutScreen(&CurrentMode); if (tempCurrentMode.FrameBuffer.Ptr) { - pAdapter->m_FrameSegment.Close(); + pAdapter->Close(ptr->screen_num); } return STATUS_SUCCESS; @@ -387,7 +402,7 @@ static NTSTATUS IoctlRequestPresentFb( (VioGpuAdapterLite*)(DeviceContext ? DeviceContext->pvDeviceExtension : 0); if (!pAdapter) { - ERR("Coudlnt' find adapter\n"); + ERR("Couldnt' find adapter\n"); return status; } @@ -398,15 +413,24 @@ static NTSTATUS IoctlRequestPresentFb( return STATUS_INVALID_USER_BUFFER; } + if (ptr->screen_num >= MAX_SCAN_OUT) { + ERR("Screen number provided by UMD: %d is greater than or equal to the maximum supported: %d by the KMD\n", + ptr->screen_num, MAX_SCAN_OUT); + WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); + return status; + } status = pAdapter->ExecutePresentDisplayZeroCopy( (BYTE*)ptr->addr, ptr->bitrate, ptr->pitch, ptr->width, - ptr->height); + ptr->height, + ptr->screen_num); - if (status != STATUS_SUCCESS) + if (status != STATUS_SUCCESS) { + ERR("ExecutePresentDisplayZeroCopy failed with status = %d\n", status); return STATUS_UNSUCCESSFUL; + } return STATUS_SUCCESS; } @@ -446,6 +470,14 @@ static NTSTATUS IoctlRequestEdid( WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return status; } + + if (edata->screen_num >= MAX_SCAN_OUT) { + ERR("Screen number provided by UMD: %d is greater than or equal to the maximum supported: %d by the KMD\n", + edata->screen_num, MAX_SCAN_OUT); + WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); + return status; + } + if (edata->mode_size == 0) { status = WdfRequestRetrieveOutputBuffer(Request, 0, (PVOID*)&edata, &bufSize); if (!NT_SUCCESS(status)) { @@ -453,14 +485,15 @@ static NTSTATUS IoctlRequestEdid( WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return status; } + //Return value from the KMDF DVServer - if (mode_list.modelist_size != 0) { - edata->mode_size = mode_list.modelist_size; + if(pAdapter->GetModeListSize(edata->screen_num) != 0) { + edata->mode_size = pAdapter->GetModeListSize(edata->screen_num); } else { edata->mode_size = QEMU_MODELIST_SIZE; } WdfRequestSetInformation(Request, sizeof(struct edid_info)); - } else if ((edata->mode_size == mode_list.modelist_size) || (edata->mode_size == QEMU_MODELIST_SIZE)) { + } else if ((edata->mode_size == pAdapter->GetModeListSize(edata->screen_num)) || (edata->mode_size == QEMU_MODELIST_SIZE)) { status = WdfRequestRetrieveOutputBuffer(Request, 0, (PVOID*)&edata, &bufSize); if (!NT_SUCCESS(status)) { ERR("Couldn't retrieve Output buffer\n"); @@ -468,14 +501,47 @@ static NTSTATUS IoctlRequestEdid( return status; } //Return value from the KMDF DVServer - RtlCopyMemory(edata->edid_data, pAdapter->GetEdidData(0), EDID_V1_BLOCK_SIZE); + RtlCopyMemory(edata->edid_data, pAdapter->GetEdidData(edata->screen_num), EDID_V1_BLOCK_SIZE); - for (unsigned int i = 0; i < edata->mode_size; i++) { - edata->mode_list[i].width = gpu_disp_mode_ext[i].XResolution; - edata->mode_list[i].height = gpu_disp_mode_ext[i].YResolution; - edata->mode_list[i].refreshrate = gpu_disp_mode_ext[i].refresh; - } + pAdapter->CopyResolution(edata->screen_num, edata); WdfRequestSetInformation(Request, sizeof(struct edid_info)); } return STATUS_SUCCESS; } + +static NTSTATUS IoctlRequestTotalScreens( + const PDEVICE_CONTEXT DeviceContext, + const size_t InputBufferLength, + const size_t OutputBufferLength, + const WDFREQUEST Request, + size_t* BytesReturned) +{ + UNREFERENCED_PARAMETER(DeviceContext); + UNREFERENCED_PARAMETER(InputBufferLength); + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(BytesReturned); + + NTSTATUS status = STATUS_UNSUCCESSFUL; + struct screen_info* mdata = NULL; + size_t bufSize; + + VioGpuAdapterLite* pAdapter = + (VioGpuAdapterLite*)(DeviceContext ? DeviceContext->pvDeviceExtension : 0); + + if (!pAdapter) { + ERR("Coudlnt' find adapter\n"); + return status; + } + + status = WdfRequestRetrieveOutputBuffer(Request, 0, (PVOID*)&mdata, &bufSize); + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); + return status; + + } + + mdata->total_screens = pAdapter->GetNumScreens(); + WdfRequestSetInformation(Request, sizeof(struct screen_info)); + + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/DVServerKMD/Queue.h b/DVServerKMD/Queue.h index 05ec51e..022a737 100644 --- a/DVServerKMD/Queue.h +++ b/DVServerKMD/Queue.h @@ -54,6 +54,13 @@ static NTSTATUS IoctlRequestEdid( const WDFREQUEST Request, size_t* BytesReturned); +static NTSTATUS IoctlRequestTotalScreens( + const PDEVICE_CONTEXT DeviceContext, + const size_t InputBufferLength, + const size_t OutputBufferLength, + const WDFREQUEST Request, + size_t * BytesReturned); + // // Events from the IoQueue object // diff --git a/DVServerKMD/debug.h b/DVServerKMD/debug.h index 2619ba2..a08eb5f 100644 --- a/DVServerKMD/debug.h +++ b/DVServerKMD/debug.h @@ -1,3 +1,13 @@ +/*=========================================================================== +; debug.h +;---------------------------------------------------------------------------- +; Copyright (C) 2021 Intel Corporation +; SPDX-License-Identifier: BSD-3-Clause +; +; File Description: +; This file declares and defines the devserverkmd logging macros +;--------------------------------------------------------------------------*/ + #ifndef _DEBUG_H #define _DEBUG_H diff --git a/DVServerKMD/edid.h b/DVServerKMD/edid.h index e7b8fca..ab0e159 100644 --- a/DVServerKMD/edid.h +++ b/DVServerKMD/edid.h @@ -1,7 +1,7 @@ /*=========================================================================== ; edid.h ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: BSD-3-Clause ;--------------------------------------------------------------------------*/ diff --git a/DVServerKMD/helper.h b/DVServerKMD/helper.h index 1fe7051..6423338 100644 --- a/DVServerKMD/helper.h +++ b/DVServerKMD/helper.h @@ -80,7 +80,6 @@ extern "C" { #include } -#define MAX_CHILDREN 4 #define MAX_VIEWS 1 #define BITS_PER_BYTE 8 diff --git a/DVServerKMD/qemu_edid.h b/DVServerKMD/qemu_edid.h index f3f4c73..0b63f59 100644 --- a/DVServerKMD/qemu_edid.h +++ b/DVServerKMD/qemu_edid.h @@ -1,7 +1,7 @@ /*=========================================================================== ; qemu_edid.h ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: BSD-3-Clause ;--------------------------------------------------------------------------*/ diff --git a/DVServerKMD/viogpu_queue.cpp b/DVServerKMD/viogpu_queue.cpp index 8f039a2..ad4b462 100644 --- a/DVServerKMD/viogpu_queue.cpp +++ b/DVServerKMD/viogpu_queue.cpp @@ -1,5 +1,5 @@ /* - * Copyright © 2021 Intel Corporation + * Copyright (C) 2021 Intel Corporation * Copyright (C) 2019-2020 Red Hat, Inc. * * Written By: Vadim Rozenfeld @@ -88,7 +88,6 @@ _IRQL_raises_(DISPATCH_LEVEL) void VioGpuQueue::Lock(KIRQL* Irql) { KIRQL SavedIrql = KeGetCurrentIrql(); - TRACING(); if (SavedIrql < DISPATCH_LEVEL) { KeAcquireSpinLock(&m_SpinLock, &SavedIrql); @@ -104,8 +103,6 @@ void VioGpuQueue::Lock(KIRQL* Irql) void VioGpuQueue::Unlock(KIRQL SavedIrql) { - TRACING(); - if (SavedIrql < DISPATCH_LEVEL) { KeReleaseSpinLock(&m_SpinLock, SavedIrql); } @@ -211,7 +208,7 @@ BOOLEAN CtrlQueue::AskDisplayInfo(PGPU_VBUFFER* buf, KEVENT* event) if (!resp_buf) { - ERR("Failed to allocate %d bytes\n", sizeof(GPU_RESP_DISP_INFO)); + ERR("Failed to allocate %d bytes\n", (int) sizeof(GPU_RESP_DISP_INFO)); return FALSE; } @@ -226,6 +223,7 @@ BOOLEAN CtrlQueue::AskDisplayInfo(PGPU_VBUFFER* buf, KEVENT* event) LARGE_INTEGER timeout = { 0 }; timeout.QuadPart = Int32x32To64(1000, -10000); + DBGPRINT("QueueBuffer, type = %d\n", cmd->type); QueueBuffer(vbuf); status = KeWaitForSingleObject(event, Executive, @@ -258,7 +256,7 @@ BOOLEAN CtrlQueue::AskEdidInfo(PGPU_VBUFFER* buf, UINT id, KEVENT* event) if (!resp_buf) { - ERR("Failed to allocate %d bytes\n", sizeof(GPU_RESP_EDID)); + ERR("Failed to allocate %d bytes\n", (int) sizeof(GPU_RESP_EDID)); return FALSE; } cmd = (PGPU_CMD_GET_EDID)AllocCmdResp(&vbuf, sizeof(GPU_CMD_GET_EDID), resp_buf, sizeof(GPU_RESP_EDID)); @@ -273,6 +271,7 @@ BOOLEAN CtrlQueue::AskEdidInfo(PGPU_VBUFFER* buf, UINT id, KEVENT* event) LARGE_INTEGER timeout = { 0 }; timeout.QuadPart = Int32x32To64(1000, -10000); + DBGPRINT("QueueBuffer, type = %d, screen = %d\n", cmd->hdr.type, cmd->scanout); QueueBuffer(vbuf); status = KeWaitForSingleObject(event, @@ -312,8 +311,7 @@ BOOLEAN CtrlQueue::GetEdidInfo(PGPU_VBUFFER buf, UINT id, PBYTE edid) return FALSE; } - PUCHAR resp_edit = resp->edid + (id * EDID_V1_BLOCK_SIZE); - RtlCopyMemory(edid, resp_edit, EDID_V1_BLOCK_SIZE); + RtlCopyMemory(edid, resp->edid, EDID_V1_BLOCK_SIZE); return TRUE; } @@ -325,6 +323,10 @@ void CtrlQueue::CreateResource(UINT res_id, UINT format, UINT width, UINT height PGPU_RES_CREATE_2D cmd; PGPU_VBUFFER vbuf; cmd = (PGPU_RES_CREATE_2D)AllocCmd(&vbuf, sizeof(*cmd)); + if (!cmd) { + ERR("Couldn't allocate %ld bytes of memory\n", sizeof(*cmd)); + return; + } RtlZeroMemory(cmd, sizeof(*cmd)); cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D; @@ -334,6 +336,7 @@ void CtrlQueue::CreateResource(UINT res_id, UINT format, UINT width, UINT height cmd->height = height; //FIXME!!! if + DBGPRINT("QueueBuffer, type = %d\n", cmd->hdr.type); QueueBuffer(vbuf); } @@ -346,6 +349,7 @@ void CtrlQueue::CreateResourceBlob(UINT res_id, PGPU_MEM_ENTRY ents, UINT nents, PGPU_VBUFFER vbuf; cmd = (PGPU_RES_CREATE_BLOB)AllocCmd(&vbuf, sizeof(*cmd)); if ((vbuf == NULL)||(cmd == NULL)) { + ERR("Couldn't allocate %ld bytes of memory\n", sizeof(*cmd)); return; } RtlZeroMemory(cmd, sizeof(*cmd)); @@ -363,6 +367,7 @@ void CtrlQueue::CreateResourceBlob(UINT res_id, PGPU_MEM_ENTRY ents, UINT nents, vbuf->data_size = sizeof(*ents) * nents; //FIXME!!! if + DBGPRINT("QueueBuffer, type = %d\n", cmd->hdr.type); QueueBuffer(vbuf); } @@ -375,11 +380,17 @@ void CtrlQueue::UnrefResource(UINT res_id) PGPU_RES_UNREF cmd; PGPU_VBUFFER vbuf; cmd = (PGPU_RES_UNREF)AllocCmd(&vbuf, sizeof(*cmd)); + if (!cmd) { + ERR("Couldn't allocate %ld bytes of memory\n", sizeof(*cmd)); + return; + } + RtlZeroMemory(cmd, sizeof(*cmd)); cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_UNREF; cmd->resource_id = res_id; + DBGPRINT("QueueBuffer, type = %d\n", cmd->hdr.type); QueueBuffer(vbuf); } @@ -396,6 +407,7 @@ void CtrlQueue::InvalBacking(UINT res_id) cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING; cmd->resource_id = res_id; + DBGPRINT("QueueBuffer, type = %d\n", cmd->hdr.type); QueueBuffer(vbuf); } @@ -407,6 +419,10 @@ void CtrlQueue::SetScanout(UINT scan_id, UINT res_id, UINT width, UINT height, U PGPU_SET_SCANOUT cmd; PGPU_VBUFFER vbuf; cmd = (PGPU_SET_SCANOUT)AllocCmd(&vbuf, sizeof(*cmd)); + if (!cmd) { + ERR("Couldn't allocate %ld bytes of memory\n", sizeof(*cmd)); + return; + } RtlZeroMemory(cmd, sizeof(*cmd)); cmd->hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT; @@ -418,6 +434,7 @@ void CtrlQueue::SetScanout(UINT scan_id, UINT res_id, UINT width, UINT height, U cmd->r.y = y; //FIXME if + DBGPRINT("QueueBuffer, type = %d, screen = %d\n", cmd->hdr.type, scan_id); QueueBuffer(vbuf); } @@ -430,6 +447,7 @@ void CtrlQueue::SetScanoutBlob(UINT scan_id, UINT res_id, UINT width, UINT heigh PGPU_VBUFFER vbuf; cmd = (PGPU_SET_SCANOUT_BLOB)AllocCmd(&vbuf, sizeof(*cmd)); if ((vbuf == NULL)||(cmd == NULL)) { + ERR("Couldn't allocate %ld bytes of memory\n", sizeof(*cmd)); return; } RtlZeroMemory(cmd, sizeof(*cmd)); @@ -453,10 +471,11 @@ void CtrlQueue::SetScanoutBlob(UINT scan_id, UINT res_id, UINT width, UINT heigh cmd->r.y = y; //FIXME if + DBGPRINT("QueueBuffer, type = %d, screen = %d\n", cmd->hdr.type, scan_id); QueueBuffer(vbuf); } -void CtrlQueue::ResFlush(UINT res_id, UINT width, UINT height, UINT x, UINT y, KEVENT* event) +void CtrlQueue::ResFlush(UINT res_id, UINT width, UINT height, UINT x, UINT y, UINT screen_num, KEVENT* event) { NTSTATUS status; @@ -466,9 +485,14 @@ void CtrlQueue::ResFlush(UINT res_id, UINT width, UINT height, UINT x, UINT y, K PGPU_RES_FLUSH cmd; PGPU_VBUFFER vbuf; cmd = (PGPU_RES_FLUSH)AllocCmd(&vbuf, sizeof(*cmd)); + if (!cmd) { + ERR("Couldn't allocate %ld bytes of memory\n", sizeof(*cmd)); + return; + } RtlZeroMemory(cmd, sizeof(*cmd)); cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH; + cmd->hdr.fence_id = screen_num; cmd->resource_id = res_id; cmd->r.width = width; cmd->r.height = height; @@ -482,16 +506,20 @@ void CtrlQueue::ResFlush(UINT res_id, UINT width, UINT height, UINT x, UINT y, K KeInitializeEvent(event, NotificationEvent, FALSE); vbuf->event = event; + DBGPRINT("QueueBuffer, type = %d, screen = %d\n", cmd->hdr.type, screen_num); QueueBuffer(vbuf); + LARGE_INTEGER timeout = { 0 }; + timeout.QuadPart = Int32x32To64(1000, -1000); + status = KeWaitForSingleObject(event, Executive, KernelMode, FALSE, - NULL); + &timeout); if (status == STATUS_TIMEOUT) { - ERR("---> Failed to ask display info\n"); + ERR("---> Timeout waiting for Resrouce Flush\n"); VioGpuDbgBreak(); // return FALSE; } @@ -506,6 +534,10 @@ void CtrlQueue::TransferToHost2D(UINT res_id, ULONG offset, UINT width, UINT hei PGPU_RES_TRANSF_TO_HOST_2D cmd; PGPU_VBUFFER vbuf; cmd = (PGPU_RES_TRANSF_TO_HOST_2D)AllocCmd(&vbuf, sizeof(*cmd)); + if (!cmd) { + ERR("Couldn't allocate %ld bytes of memory\n", sizeof(*cmd)); + return; + } RtlZeroMemory(cmd, sizeof(*cmd)); cmd->hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D; @@ -521,6 +553,7 @@ void CtrlQueue::TransferToHost2D(UINT res_id, ULONG offset, UINT width, UINT hei cmd->hdr.fence_id = *fence_id; } + DBGPRINT("QueueBuffer, type = %d\n", cmd->hdr.type); QueueBuffer(vbuf); } @@ -532,6 +565,10 @@ void CtrlQueue::AttachBacking(UINT res_id, PGPU_MEM_ENTRY ents, UINT nents) PGPU_RES_ATTACH_BACKING cmd; PGPU_VBUFFER vbuf; cmd = (PGPU_RES_ATTACH_BACKING)AllocCmd(&vbuf, sizeof(*cmd)); + if (!cmd) { + ERR("Couldn't allocate %ld bytes of memory\n", sizeof(*cmd)); + return; + } RtlZeroMemory(cmd, sizeof(*cmd)); cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING; @@ -541,6 +578,7 @@ void CtrlQueue::AttachBacking(UINT res_id, PGPU_MEM_ENTRY ents, UINT nents) vbuf->data_buf = ents; vbuf->data_size = sizeof(*ents) * nents; + DBGPRINT("QueueBuffer, type = %d\n", cmd->hdr.type); QueueBuffer(vbuf); } diff --git a/DVServerKMD/viogpu_queue.h b/DVServerKMD/viogpu_queue.h index 017634c..1634751 100644 --- a/DVServerKMD/viogpu_queue.h +++ b/DVServerKMD/viogpu_queue.h @@ -1,5 +1,5 @@ /* - * Copyright © 2021 Intel Corporation + * Copyright (C) 2021 Intel Corporation * Copyright (C) 2019-2020 Red Hat, Inc. * * Written By: Vadim Rozenfeld @@ -184,7 +184,7 @@ class CtrlQueue : public VioGpuQueue void InvalBacking(UINT id); void SetScanout(UINT scan_id, UINT res_id, UINT width, UINT height, UINT x, UINT y); void SetScanoutBlob(UINT scan_id, UINT res_id, UINT width, UINT height, UINT format, UINT x, UINT y); - void ResFlush(UINT res_id, UINT width, UINT height, UINT x, UINT y, KEVENT* event); + void ResFlush(UINT res_id, UINT width, UINT height, UINT x, UINT y, UINT screen_num, KEVENT* event); void TransferToHost2D(UINT res_id, ULONG offset, UINT width, UINT height, UINT x, UINT y, PUINT fence_id); void AttachBacking(UINT res_id, PGPU_MEM_ENTRY ents, UINT nents); BOOLEAN GetDisplayInfo(PGPU_VBUFFER buf, UINT id, PULONG xres, PULONG yres); diff --git a/DVServerKMD/viogpulite.cpp b/DVServerKMD/viogpulite.cpp index a2136aa..0d92452 100644 --- a/DVServerKMD/viogpulite.cpp +++ b/DVServerKMD/viogpulite.cpp @@ -1,5 +1,5 @@ /* - * Copyright © 2021 Intel Corporation + * Copyright (C) 2021 Intel Corporation * Copyright (C) 2019-2020 Red Hat, Inc. * * Written By: Vadim Rozenfeld @@ -35,7 +35,6 @@ #include "baseobj.h" #include "bitops.h" #include "qemu_edid.h" -#include "edid.h" extern "C" { #include "..\EDIDParser\edidshared.h" @@ -55,7 +54,8 @@ extern "C" int _fltused = 0; static UINT g_InstanceId = 0; PAGED_CODE_SEG_BEGIN -VioGpuAdapterLite::VioGpuAdapterLite(_In_ PVOID pvDeviceContext) : IVioGpuAdapterLite(pvDeviceContext) + +ScreenInfo::ScreenInfo() { PAGED_CODE(); TRACING(); @@ -64,8 +64,42 @@ VioGpuAdapterLite::VioGpuAdapterLite(_In_ PVOID pvDeviceContext) : IVioGpuAdapte m_ModeCount = 0; m_ModeNumbers = NULL; m_CurrentMode = 0; - m_Id = g_InstanceId++; + m_CustomMode = 0; + mode_list.modelist_size = 0; m_pFrameBuf = NULL; + m_FlushCount = 0; +} + +ScreenInfo::~ScreenInfo() +{ + Reset(); + m_CurrentMode = 0; + m_CustomMode = 0; + m_ModeCount = 0; +} + +void ScreenInfo::Reset() +{ + if (m_ModeInfo) { + delete[] m_ModeInfo; + m_ModeInfo = NULL; + } + if (m_ModeNumbers) { + delete[] m_ModeNumbers; + m_ModeNumbers = NULL; + } + RtlZeroMemory(&mode_list, sizeof(output_modelist)); + mode_list.modelist_size = 0; + RtlZeroMemory(&gpu_disp_mode_ext, sizeof(GPU_DISP_MODE_EXT) * MAX_MODELIST_SIZE); + m_pFrameBuf = NULL; +} + +VioGpuAdapterLite::VioGpuAdapterLite(_In_ PVOID pvDeviceContext) : IVioGpuAdapterLite(pvDeviceContext) +{ + PAGED_CODE(); + TRACING(); + + m_Id = g_InstanceId++; m_pCursorBuf = NULL; m_PendingWorks = 0; KeInitializeEvent(&m_ConfigUpdateEvent, @@ -81,16 +115,11 @@ VioGpuAdapterLite::~VioGpuAdapterLite(void) PAGED_CODE(); TRACING(); DestroyCursor(); - DestroyFrameBufferObj(TRUE); + for (UINT32 i = 0; i < m_u32NumScanouts; i++) { + DestroyFrameBufferObj(i, TRUE); + } VioGpuAdapterLiteClose(); HWClose(); - delete[] m_ModeInfo; - delete[] m_ModeNumbers; - m_ModeInfo = NULL; - m_ModeNumbers = NULL; - m_CurrentMode = 0; - m_CustomMode = 0; - m_ModeCount = 0; m_Id = 0; g_InstanceId--; } @@ -116,36 +145,44 @@ NTSTATUS VioGpuAdapterLite::SetCurrentModeExt(CURRENT_MODE* pCurrentMode) PAGED_CODE(); TRACING(); - DBGPRINT("Mode = %dx%d\n", pCurrentMode->SrcModeWidth, pCurrentMode->SrcModeHeight); - if (!pCurrentMode) + if (!pCurrentMode) { + ERR("Mode pointer is NULL\n"); return status; + } - for (ULONG idx = 0; idx < GetModeCount(); idx++) + DBGPRINT("ScreenNum = %d, Mode = %dx%d\n", pCurrentMode->DispInfo.TargetId, pCurrentMode->DispInfo.Width, pCurrentMode->DispInfo.Height); + + for (ULONG idx = 0; idx < m_screen[pCurrentMode->DispInfo.TargetId].GetModeCount(); idx++) { - if (!IsSameMode(&m_ModeInfo[idx], pCurrentMode)) + status = STATUS_SUCCESS; + + if (!IsSameMode(&m_screen[pCurrentMode->DispInfo.TargetId].m_ModeInfo[idx], pCurrentMode)) continue; - DestroyFrameBufferObj(FALSE); - CreateFrameBufferObj(&m_ModeInfo[idx], pCurrentMode); - DBGPRINT("device %d: setting current mode (%d x %d)\n", - m_Id, m_ModeInfo[idx].VisScreenWidth, - m_ModeInfo[idx].VisScreenHeight); - status = STATUS_SUCCESS; + if (!m_screen[pCurrentMode->DispInfo.TargetId].m_FlushCount) { + DestroyFrameBufferObj(pCurrentMode->DispInfo.TargetId, FALSE); + CreateFrameBufferObj(&m_screen[pCurrentMode->DispInfo.TargetId].m_ModeInfo[idx], pCurrentMode); + DBGPRINT("screen %d: setting current mode (%d x %d)\n", + pCurrentMode->DispInfo.TargetId, m_screen[pCurrentMode->DispInfo.TargetId].m_ModeInfo[idx].VisScreenWidth, + m_screen[pCurrentMode->DispInfo.TargetId].m_ModeInfo[idx].VisScreenHeight); + } else { + DBGPRINT("For screen %d Pending flush (%d) with Qemu so not sending another request\n", + pCurrentMode->DispInfo.TargetId, m_screen[pCurrentMode->DispInfo.TargetId].m_FlushCount); + } break; } return status; } -NTSTATUS VioGpuAdapterLite::VioGpuAdapterLiteInit(DXGK_DISPLAY_INFORMATION* pDispInfo) +NTSTATUS VioGpuAdapterLite::VioGpuAdapterLiteInit() { PAGED_CODE(); NTSTATUS status = STATUS_SUCCESS; TRACING(); - UNREFERENCED_PARAMETER(pDispInfo); if (IsHardwareInit()) { DBGPRINT("Already Initialized\n"); VioGpuDbgBreak(); @@ -199,9 +236,9 @@ NTSTATUS VioGpuAdapterLite::VioGpuAdapterLiteInit(DXGK_DISPLAY_INFORMATION* pDis virtio_get_config(&m_VioDev, FIELD_OFFSET(GPU_CONFIG, num_scanouts), &m_u32NumScanouts, sizeof(m_u32NumScanouts)); - if (m_u32NumScanouts > MAX_CHILDREN) { + if (m_u32NumScanouts > MAX_SCAN_OUT) { ERR("Number of displays provided by Hypervisor: %d are more than what the KMD supports: %d\n", - m_u32NumScanouts, MAX_CHILDREN); + m_u32NumScanouts, MAX_SCAN_OUT); status = STATUS_INSUFFICIENT_RESOURCES; VioGpuDbgBreak(); break; @@ -267,12 +304,14 @@ NTSTATUS VioGpuAdapterLite::SetPowerState(DEVICE_POWER_STATE DevicePowerState) { case PowerDeviceUnspecified: case PowerDeviceD0: { - VioGpuAdapterLiteInit(&m_CurrentModeInfo.DispInfo); + VioGpuAdapterLiteInit(); } break; case PowerDeviceD1: case PowerDeviceD2: case PowerDeviceD3: { - DestroyFrameBufferObj(TRUE); + for (UINT32 i = 0; i < m_u32NumScanouts; i++) { + DestroyFrameBufferObj(i, TRUE); + } VioGpuAdapterLiteClose(); m_CurrentModeInfo.Flags.FrameBufferIsActive = FALSE; m_CurrentModeInfo.FrameBuffer.Ptr = NULL; @@ -336,7 +375,7 @@ PBYTE VioGpuAdapterLite::GetEdidData(UINT Id) { PAGED_CODE(); - return m_bEDID ? m_EDIDs[Id] : (PBYTE)(&g_gpu_edid);//.data; + return m_bEDID ? m_screen[Id].m_EDIDs : (PBYTE)(&g_gpu_edid);//.data; } NTSTATUS VioGpuAdapterLite::HWInit(WDFCMRESLIST pResList, DXGK_DISPLAY_INFORMATION* pDispInfo) @@ -363,7 +402,7 @@ NTSTATUS VioGpuAdapterLite::HWInit(WDFCMRESLIST pResList, DXGK_DISPLAY_INFORMATI break; } - status = VioGpuAdapterLiteInit(pDispInfo); + status = VioGpuAdapterLiteInit(); if (!NT_SUCCESS(status)) { ERR("Failed initialize adapter %x\n", status); @@ -432,21 +471,18 @@ NTSTATUS VioGpuAdapterLite::HWInit(WDFCMRESLIST pResList, DXGK_DISPLAY_INFORMATI //FIXME!!! update and validate size properly req_size = max(0x800000, req_size); - if (fb_pa.QuadPart != 0LL) { - pDispInfo->PhysicAddress = fb_pa; - } - if (fb_pa.QuadPart == 0 || fb_size < req_size) { fb_pa.QuadPart = 0; fb_size = req_size; } - if (!m_FrameSegment.Init(req_size, NULL)) - { - ERR("Failed to allocate FB memory segment\n"); - status = STATUS_INSUFFICIENT_RESOURCES; - VioGpuDbgBreak(); - return status; + for (UINT32 i = 0; i < m_u32NumScanouts; i++) { + if (!m_screen[i].m_FrameSegment.Init(req_size, NULL)) { + ERR("Failed to allocate FB memory segment\n"); + status = STATUS_INSUFFICIENT_RESOURCES; + VioGpuDbgBreak(); + return status; + } } if (!m_CursorSegment.Init(POINTER_SIZE * POINTER_SIZE * 4, NULL)) @@ -483,7 +519,9 @@ NTSTATUS VioGpuAdapterLite::HWClose(void) ObDereferenceObject(m_pWorkThread); - m_FrameSegment.Close(); + for (UINT32 i = 0; i < m_u32NumScanouts; i++) { + m_screen[i].m_FrameSegment.Close(); + } m_CursorSegment.Close(); return STATUS_SUCCESS; @@ -544,7 +582,8 @@ NTSTATUS VioGpuAdapterLite::ExecutePresentDisplayZeroCopy( _In_ UINT SrcBytesPerPixel, _In_ LONG SrcPitch, _In_ UINT SrcWidth, - _In_ UINT SrcHeight) + _In_ UINT SrcHeight, + _In_ UINT ScreenNum) { PAGED_CODE(); TRACING(); @@ -552,35 +591,33 @@ NTSTATUS VioGpuAdapterLite::ExecutePresentDisplayZeroCopy( BLT_INFO SrcBltInfo = { 0 }; BLT_INFO DstBltInfo = { 0 }; RECT rect = { 0 }; + NTSTATUS status; - UNREFERENCED_PARAMETER(SrcBytesPerPixel); - UNREFERENCED_PARAMETER(SrcPitch); - - DBGPRINT("SrcBytesPerPixel = %d DstBitPerPixel = %dx%d\n", - SrcBytesPerPixel, SrcWidth, SrcHeight); + DBGPRINT("SrcBytesPerPixel = %d Mode = %dx%d\n", SrcBytesPerPixel, SrcWidth, SrcHeight); CURRENT_MODE tempCurrentMode = { 0 }; tempCurrentMode.DispInfo.Width = SrcWidth; tempCurrentMode.DispInfo.Height = SrcHeight; tempCurrentMode.DispInfo.Pitch = SrcPitch; + tempCurrentMode.DispInfo.TargetId = ScreenNum; tempCurrentMode.DispInfo.ColorFormat = D3DDDIFMT_X8R8G8B8; tempCurrentMode.FrameBuffer.Ptr = SrcAddr; - SetCurrentModeExt(&tempCurrentMode); + status = SetCurrentModeExt(&tempCurrentMode); DBGPRINT("offset = (XxYxWxH) (%dx%dx%dx%d) vs (%dx%dx%dx%d)\n", rect.left, rect.top, SrcWidth, - SrcWidth, + SrcHeight, 0, 0, SrcWidth, SrcHeight); - m_FrameSegment.Close(); + Close(ScreenNum); - return STATUS_SUCCESS; + return status; } VOID VioGpuAdapterLite::BlackOutScreen(CURRENT_MODE* pCurrentMod) @@ -602,10 +639,12 @@ VOID VioGpuAdapterLite::BlackOutScreen(CURRENT_MODE* pCurrentMod) //FIXME!!! rotation - resid = m_pFrameBuf->GetId(); + resid = m_screen[pCurrentMod->DispInfo.TargetId].m_pFrameBuf->GetId(); m_CtrlQueue.TransferToHost2D(resid, 0UL, pCurrentMod->DispInfo.Width, pCurrentMod->DispInfo.Height, 0, 0, NULL); - m_CtrlQueue.ResFlush(resid, pCurrentMod->DispInfo.Width, pCurrentMod->DispInfo.Height, 0, 0, &m_FlushEvent); + m_screen[pCurrentMod->DispInfo.TargetId].m_FlushCount++; + m_CtrlQueue.ResFlush(resid, pCurrentMod->DispInfo.Width, pCurrentMod->DispInfo.Height, 0, 0, pCurrentMod->DispInfo.TargetId, + &m_screen[pCurrentMod->DispInfo.TargetId].m_FlushEvent); } } @@ -701,7 +740,7 @@ NTSTATUS VioGpuAdapterLite::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSI return STATUS_UNSUCCESSFUL; } -BOOLEAN VioGpuAdapterLite::GetDisplayInfo(void) +BOOLEAN VioGpuAdapterLite::GetDisplayInfo(UINT32 screen_num) { PAGED_CODE(); TRACING(); @@ -710,33 +749,31 @@ BOOLEAN VioGpuAdapterLite::GetDisplayInfo(void) ULONG xres = 0; ULONG yres = 0; - for (UINT32 i = 0; i < m_u32NumScanouts; i++) { - if (m_CtrlQueue.AskDisplayInfo(&vbuf, &m_DisplayInfoEvent)) { - m_CtrlQueue.GetDisplayInfo(vbuf, i, &xres, &yres); - m_CtrlQueue.ReleaseBuffer(vbuf); - if (xres && yres) { - DBGPRINT("(%dx%d)\n", xres, yres); - SetCustomDisplay((USHORT)xres, (USHORT)yres); - } + if (m_CtrlQueue.AskDisplayInfo(&vbuf, &m_screen[screen_num].m_DisplayInfoEvent)) { + m_CtrlQueue.GetDisplayInfo(vbuf, screen_num, &xres, &yres); + m_CtrlQueue.ReleaseBuffer(vbuf); + if (xres && yres) { + DBGPRINT("(%dx%d)\n", xres, yres); + m_screen[screen_num].SetCustomDisplay((USHORT)xres, (USHORT)yres); } } return TRUE; } -void VioGpuAdapterLite::ProcessEdid(void) +void VioGpuAdapterLite::ProcessEdid(UINT32 screen_num) { PAGED_CODE(); if (virtio_is_feature_enabled(m_u64HostFeatures, VIRTIO_GPU_F_EDID)) { - GetEdids(); - AddEdidModes(); + GetEdids(screen_num); + AddEdidModes(screen_num); } else { return; } } -BOOLEAN VioGpuAdapterLite::GetEdids(void) +BOOLEAN VioGpuAdapterLite::GetEdids(UINT32 screen_num) { PAGED_CODE(); @@ -744,13 +781,11 @@ BOOLEAN VioGpuAdapterLite::GetEdids(void) PGPU_VBUFFER vbuf = NULL; - for (UINT32 i = 0; i < m_u32NumScanouts; i++) { - if (m_CtrlQueue.AskEdidInfo(&vbuf, i, &m_EdidEvent) && - m_CtrlQueue.GetEdidInfo(vbuf, i, m_EDIDs[i])) { - m_bEDID = TRUE; - } - m_CtrlQueue.ReleaseBuffer(vbuf); + if (m_CtrlQueue.AskEdidInfo(&vbuf, screen_num, &m_screen[screen_num].m_EdidEvent) && + m_CtrlQueue.GetEdidInfo(vbuf, screen_num, m_screen[screen_num].m_EDIDs)) { + m_bEDID = TRUE; } + m_CtrlQueue.ReleaseBuffer(vbuf); return TRUE; } @@ -768,31 +803,37 @@ GPU_DISP_MODE gpu_disp_modes[16] = {0, 0}, }; -GPU_DISP_MODE_EXT gpu_disp_mode_ext[MAX_MODELIST_SIZE] = { 0 }; -output_modelist mode_list = { 0 }; +VOID VioGpuAdapterLite::CopyResolution(UINT32 screen_num, struct edid_info* edata) +{ + for (unsigned int i = 0; i < edata->mode_size; i++) { + edata->mode_list[i].width = m_screen[screen_num].gpu_disp_mode_ext[i].XResolution; + edata->mode_list[i].height = m_screen[screen_num].gpu_disp_mode_ext[i].YResolution; + edata->mode_list[i].refreshrate = m_screen[screen_num].gpu_disp_mode_ext[i].refresh; + } +} -void VioGpuAdapterLite::AddEdidModes(void) +void VioGpuAdapterLite::AddEdidModes(UINT32 screen_num) { PAGED_CODE(); TRACING(); - if (parse_edid_data(GetEdidData(0), &mode_list) != 0) { + if (parse_edid_data(GetEdidData(screen_num), &m_screen[screen_num].mode_list) != 0) { for (unsigned int i = 0; i < QEMU_MODELIST_SIZE; i++) { - gpu_disp_mode_ext[i].XResolution = (USHORT)qemu_modelist[i].x; - gpu_disp_mode_ext[i].YResolution = (USHORT)qemu_modelist[i].y; - gpu_disp_mode_ext[i].refresh = qemu_modelist[i].rr; + m_screen[screen_num].gpu_disp_mode_ext[i].XResolution = (USHORT)qemu_modelist[i].x; + m_screen[screen_num].gpu_disp_mode_ext[i].YResolution = (USHORT)qemu_modelist[i].y; + m_screen[screen_num].gpu_disp_mode_ext[i].refresh = qemu_modelist[i].rr; } } else { for (unsigned int i = 0; i < QEMU_MODELIST_SIZE; i++) { - gpu_disp_mode_ext[i].XResolution = (USHORT)mode_list.modelist[i].width; - gpu_disp_mode_ext[i].YResolution = (USHORT)mode_list.modelist[i].height; - gpu_disp_mode_ext[i].refresh = mode_list.modelist[i].refresh_rate; + m_screen[screen_num].gpu_disp_mode_ext[i].XResolution = (USHORT)m_screen[screen_num].mode_list.modelist[i].width; + m_screen[screen_num].gpu_disp_mode_ext[i].YResolution = (USHORT)m_screen[screen_num].mode_list.modelist[i].height; + m_screen[screen_num].gpu_disp_mode_ext[i].refresh = m_screen[screen_num].mode_list.modelist[i].refresh_rate; } } } -void VioGpuAdapterLite::SetVideoModeInfo(UINT Idx, PGPU_DISP_MODE_EXT pModeInfo) +void ScreenInfo::SetVideoModeInfo(UINT Idx, PGPU_DISP_MODE_EXT pModeInfo) { PAGED_CODE(); @@ -807,7 +848,7 @@ void VioGpuAdapterLite::SetVideoModeInfo(UINT Idx, PGPU_DISP_MODE_EXT pModeInfo) pMode->ScreenStride = (pModeInfo->XResolution * bytes_pp + 3) & ~0x3; } -void VioGpuAdapterLite::SetCustomDisplay(_In_ USHORT xres, _In_ USHORT yres) +void ScreenInfo::SetCustomDisplay(_In_ USHORT xres, _In_ USHORT yres) { PAGED_CODE(); @@ -835,97 +876,96 @@ NTSTATUS VioGpuAdapterLite::GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo) TRACING(); - UINT ModeCount = 0; - delete[] m_ModeInfo; - delete[] m_ModeNumbers; - m_ModeInfo = NULL; - m_ModeNumbers = NULL; + for (UINT32 i = 0; i < m_u32NumScanouts; i++) { - ProcessEdid(); - while ((gpu_disp_mode_ext[ModeCount].XResolution >= MIN_WIDTH_SIZE) && - (gpu_disp_mode_ext[ModeCount].YResolution >= MIN_HEIGHT_SIZE)) ModeCount++; + UINT ModeCount = 0; + m_screen[i].Reset(); - ModeCount += 2; - m_ModeInfo = new (PagedPool) VIDEO_MODE_INFORMATION[ModeCount]; - if (!m_ModeInfo) - { - Status = STATUS_NO_MEMORY; - ERR("VioGpuAdapterLite::GetModeList failed to allocate m_ModeInfo memory\n"); - return Status; - } - RtlZeroMemory(m_ModeInfo, sizeof(VIDEO_MODE_INFORMATION) * ModeCount); + ProcessEdid(i); + while ((m_screen[i].gpu_disp_mode_ext[ModeCount].XResolution >= MIN_WIDTH_SIZE) && + (m_screen[i].gpu_disp_mode_ext[ModeCount].YResolution >= MIN_HEIGHT_SIZE)) ModeCount++; - m_ModeNumbers = new (PagedPool) USHORT[ModeCount]; - if (!m_ModeNumbers) - { - Status = STATUS_NO_MEMORY; - ERR("VioGpuAdapterLite::GetModeList failed to allocate m_ModeNumbers memory\n"); - return Status; - } - RtlZeroMemory(m_ModeNumbers, sizeof(USHORT) * ModeCount); - m_CurrentMode = 0; - DBGPRINT("m_ModeInfo = 0x%p, m_ModeNumbers = 0x%p\n", m_ModeInfo, m_ModeNumbers); + ModeCount += 2; + m_screen[i].m_ModeInfo = new (PagedPool) VIDEO_MODE_INFORMATION[ModeCount]; + if (!m_screen[i].m_ModeInfo) + { + Status = STATUS_NO_MEMORY; + ERR("VioGpuAdapterLite::GetModeList failed to allocate m_ModeInfo memory\n"); + return Status; + } + RtlZeroMemory(m_screen[i].m_ModeInfo, sizeof(VIDEO_MODE_INFORMATION) * ModeCount); - pDispInfo->Height = max(pDispInfo->Height, MIN_HEIGHT_SIZE); - pDispInfo->Width = max(pDispInfo->Width, MIN_WIDTH_SIZE); - pDispInfo->ColorFormat = D3DDDIFMT_X8R8G8B8; - pDispInfo->Pitch = (BPPFromPixelFormat(pDispInfo->ColorFormat) / BITS_PER_BYTE) * pDispInfo->Width; + m_screen[i].m_ModeNumbers = new (PagedPool) USHORT[ModeCount]; + if (!m_screen[i].m_ModeNumbers) + { + Status = STATUS_NO_MEMORY; + ERR("VioGpuAdapterLite::GetModeList failed to allocate m_ModeNumbers memory\n"); + return Status; + } + RtlZeroMemory(m_screen[i].m_ModeNumbers, sizeof(USHORT) * ModeCount); + m_screen[i].m_CurrentMode = 0; + DBGPRINT("Screen = %d, m_ModeInfo = 0x%p, m_ModeNumbers = 0x%p\n", i, m_screen[i].m_ModeInfo, m_screen[i].m_ModeNumbers); - USHORT SuitableModeCount; - USHORT CurrentMode; + pDispInfo->Height = max(pDispInfo->Height, MIN_HEIGHT_SIZE); + pDispInfo->Width = max(pDispInfo->Width, MIN_WIDTH_SIZE); + pDispInfo->ColorFormat = D3DDDIFMT_X8R8G8B8; + pDispInfo->Pitch = (BPPFromPixelFormat(pDispInfo->ColorFormat) / BITS_PER_BYTE) * pDispInfo->Width; - for (CurrentMode = 0, SuitableModeCount = 0; - CurrentMode < ModeCount - 2; - CurrentMode++) - { + USHORT SuitableModeCount; + USHORT CurrentMode; - PGPU_DISP_MODE_EXT tmpModeInfo = &gpu_disp_mode_ext[CurrentMode]; + for (CurrentMode = 0, SuitableModeCount = 0; + CurrentMode < ModeCount - 2; + CurrentMode++) + { - DBGPRINT("modes[%d] x_res = %d, y_res = %d\n", - CurrentMode, tmpModeInfo->XResolution, tmpModeInfo->YResolution); + PGPU_DISP_MODE_EXT tmpModeInfo = &m_screen[i].gpu_disp_mode_ext[CurrentMode]; - if (tmpModeInfo->XResolution >= pDispInfo->Width && - tmpModeInfo->YResolution >= pDispInfo->Height) - { - m_ModeNumbers[SuitableModeCount] = SuitableModeCount; - SetVideoModeInfo(SuitableModeCount, tmpModeInfo); - if (tmpModeInfo->XResolution == NOM_WIDTH_SIZE && - tmpModeInfo->YResolution == NOM_HEIGHT_SIZE) + DBGPRINT("modes[%d] x_res = %d, y_res = %d\n", + CurrentMode, tmpModeInfo->XResolution, tmpModeInfo->YResolution); + + if (tmpModeInfo->XResolution >= pDispInfo->Width && + tmpModeInfo->YResolution >= pDispInfo->Height) { - m_CurrentMode = SuitableModeCount; + m_screen[i].m_ModeNumbers[SuitableModeCount] = SuitableModeCount; + m_screen[i].SetVideoModeInfo(SuitableModeCount, tmpModeInfo); + if (tmpModeInfo->XResolution == NOM_WIDTH_SIZE && + tmpModeInfo->YResolution == NOM_HEIGHT_SIZE) + { + m_screen[i].m_CurrentMode = SuitableModeCount; + } + SuitableModeCount++; } - SuitableModeCount++; } - } - if (SuitableModeCount == 0) - { - ERR("No video modes supported\n"); - Status = STATUS_UNSUCCESSFUL; - } + if (SuitableModeCount == 0) + { + ERR("No video modes supported\n"); + Status = STATUS_UNSUCCESSFUL; + } - m_CustomMode = SuitableModeCount; - for (CurrentMode = SuitableModeCount; - CurrentMode < SuitableModeCount + 2; - CurrentMode++) - { - m_ModeNumbers[CurrentMode] = CurrentMode; - memcpy(&m_ModeInfo[CurrentMode], &m_ModeInfo[m_CurrentMode], sizeof(VIDEO_MODE_INFORMATION)); - } + m_screen[i].m_CustomMode = SuitableModeCount; + for (CurrentMode = SuitableModeCount; + CurrentMode < SuitableModeCount + 2; + CurrentMode++) + { + m_screen[i].m_ModeNumbers[CurrentMode] = CurrentMode; + memcpy(&m_screen[i].m_ModeInfo[CurrentMode], &m_screen[i].m_ModeInfo[m_screen[i].m_CurrentMode], sizeof(VIDEO_MODE_INFORMATION)); + } - m_ModeCount = SuitableModeCount + 2; - DBGPRINT("ModeCount filtered %d\n", m_ModeCount); + m_screen[i].m_ModeCount = SuitableModeCount + 2; + DBGPRINT("ModeCount filtered %d\n", m_screen[i].m_ModeCount); - GetDisplayInfo(); + GetDisplayInfo(i); - for (ULONG idx = 0; idx < GetModeCount(); idx++) - { - DBGPRINT("type %x, XRes = %d, YRes = %d\n", - m_ModeNumbers[idx], - m_ModeInfo[idx].VisScreenWidth, - m_ModeInfo[idx].VisScreenHeight); + for (ULONG idx = 0; idx < m_screen[i].GetModeCount(); idx++) + { + DBGPRINT("type %x, XRes = %d, YRes = %d\n", + m_screen[i].m_ModeNumbers[idx], + m_screen[i].m_ModeInfo[idx].VisScreenWidth, + m_screen[i].m_ModeInfo[idx].VisScreenHeight); + } } - return Status; } PAGED_CODE_SEG_END @@ -1012,7 +1052,9 @@ void VioGpuAdapterLite::ConfigChanged(void) virtio_get_config(&m_VioDev, FIELD_OFFSET(GPU_CONFIG, events_read), &events_read, sizeof(m_u32NumScanouts)); if (events_read & VIRTIO_GPU_EVENT_DISPLAY) { - GetDisplayInfo(); + for (UINT32 i = 0; i < m_u32NumScanouts; i++) { + GetDisplayInfo(i); + } events_clear |= VIRTIO_GPU_EVENT_DISPLAY; virtio_set_config(&m_VioDev, FIELD_OFFSET(GPU_CONFIG, events_clear), &events_clear, sizeof(m_u32NumScanouts)); @@ -1050,9 +1092,16 @@ VOID VioGpuAdapterLite::DpcRoutine(void) } switch (pcmd->type) { + case VIRTIO_GPU_CMD_RESOURCE_FLUSH: + if (m_screen[pcmd->fence_id].m_FlushCount > 0) { + m_screen[pcmd->fence_id].m_FlushCount--; + DBGPRINT("Screen id = %d, m_FlushCount = %d\n", pcmd->fence_id, m_screen[pcmd->fence_id].m_FlushCount); + } else { + ERR("Screen is %d, Flush Count is %d\n", (int) pcmd->fence_id, + m_screen[pcmd->fence_id].m_FlushCount); + } case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: case VIRTIO_GPU_CMD_GET_EDID: - case VIRTIO_GPU_CMD_RESOURCE_FLUSH: { ASSERT(evnt); KeSetEvent(evnt, IO_NO_INCREMENT, FALSE); @@ -1062,7 +1111,7 @@ VOID VioGpuAdapterLite::DpcRoutine(void) ERR("Unknown cmd type 0x%x\n", resp->type); break; } - }; + } } if ((reason & ISR_REASON_CURSOR)) { while ((pvbuf = m_CursorQueue.DequeueCursor(&len)) != NULL) @@ -1107,9 +1156,9 @@ void VioGpuAdapterLite::CreateFrameBufferObj(PVIDEO_MODE_INFORMATION pModeInfo, VioGpuObj* obj; PAGED_CODE(); TRACING(); - DBGPRINT("%d: (%d x %d)\n", m_Id, + DBGPRINT("%d: %d, (%d x %d)\n", m_Id, pCurrentMode->DispInfo.TargetId, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight); - ASSERT(m_pFrameBuf == NULL); + ASSERT(m_screen[pCurrentMode->DispInfo.TargetId].m_pFrameBuf == NULL); size = pModeInfo->ScreenStride * pModeInfo->VisScreenHeight; format = ColorFormat(pCurrentMode->DispInfo.ColorFormat); DBGPRINT("(%d -> %d)\n", pCurrentMode->DispInfo.ColorFormat, format); @@ -1121,14 +1170,14 @@ void VioGpuAdapterLite::CreateFrameBufferObj(PVIDEO_MODE_INFORMATION pModeInfo, // Update the frame segment based on the current mode if (pCurrentMode->FrameBuffer.Ptr) { - m_FrameSegment.InitExt(size, pCurrentMode->FrameBuffer.Ptr); - } else if (m_FrameSegment.GetFbVAddr() && size > m_FrameSegment.GetSize()) { - m_FrameSegment.Close(); - m_FrameSegment.Init(size, NULL); + m_screen[pCurrentMode->DispInfo.TargetId].m_FrameSegment.InitExt(size, pCurrentMode->FrameBuffer.Ptr); + } else if (m_screen[pCurrentMode->DispInfo.TargetId].m_FrameSegment.GetFbVAddr() && size > m_screen[pCurrentMode->DispInfo.TargetId].m_FrameSegment.GetSize()) { + m_screen[pCurrentMode->DispInfo.TargetId].m_FrameSegment.Close(); + m_screen[pCurrentMode->DispInfo.TargetId].m_FrameSegment.Init(size, NULL); } obj = new(NonPagedPoolNx) VioGpuObj(); - if (!obj->Init(size, &m_FrameSegment)) + if (!obj->Init(size, &m_screen[pCurrentMode->DispInfo.TargetId].m_FrameSegment)) { ERR("Failed to init obj size = %d\n", size); delete obj; @@ -1139,28 +1188,31 @@ void VioGpuAdapterLite::CreateFrameBufferObj(PVIDEO_MODE_INFORMATION pModeInfo, if (m_bBlobSupported) { - m_CtrlQueue.SetScanoutBlob(0/*FIXME m_Id*/, resid, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight, format, 0, 0); + m_CtrlQueue.SetScanoutBlob(pCurrentMode->DispInfo.TargetId, resid, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight, format, 0, 0); } else { - m_CtrlQueue.SetScanout(0/*FIXME m_Id*/, resid, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight, 0, 0); + m_CtrlQueue.SetScanout(pCurrentMode->DispInfo.TargetId, resid, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight, 0, 0); } m_CtrlQueue.TransferToHost2D(resid, 0, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight, 0, 0, NULL); - m_CtrlQueue.ResFlush(resid, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight, 0, 0, &m_FlushEvent); - m_pFrameBuf = obj; + m_screen[pCurrentMode->DispInfo.TargetId].m_FlushCount++; + DBGPRINT("Screen num = %d, flushcount = %d\n", pCurrentMode->DispInfo.TargetId, m_screen[pCurrentMode->DispInfo.TargetId].m_FlushCount); + m_CtrlQueue.ResFlush(resid, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight, 0, 0, pCurrentMode->DispInfo.TargetId, + &m_screen[pCurrentMode->DispInfo.TargetId].m_FlushEvent); + m_screen[pCurrentMode->DispInfo.TargetId].m_pFrameBuf = obj; pCurrentMode->FrameBuffer.Ptr = obj->GetVirtualAddress(); pCurrentMode->Flags.FrameBufferIsActive = TRUE; } -void VioGpuAdapterLite::DestroyFrameBufferObj(BOOLEAN bReset) +void VioGpuAdapterLite::DestroyFrameBufferObj(UINT32 screen_num, BOOLEAN bReset) { PAGED_CODE(); TRACING(); UINT resid = 0; - if (m_pFrameBuf != NULL) + if (m_screen[screen_num].m_pFrameBuf != NULL) { - resid = (UINT)m_pFrameBuf->GetId(); + resid = (UINT)m_screen[screen_num].m_pFrameBuf->GetId(); //if (bReset == TRUE) { // m_CtrlQueue.SetScanout(0/*FIXME m_Id*/, resid, 1024, 768, 0, 0); // m_CtrlQueue.TransferToHost2D(resid, 0, 1024, 768, 0, 0, NULL); @@ -1172,8 +1224,8 @@ void VioGpuAdapterLite::DestroyFrameBufferObj(BOOLEAN bReset) if (bReset == TRUE) { m_CtrlQueue.SetScanout(0/*FIXME m_Id*/, 0, 0, 0, 0, 0); } - delete m_pFrameBuf; - m_pFrameBuf = NULL; + delete m_screen[screen_num].m_pFrameBuf; + m_screen[screen_num].m_pFrameBuf = NULL; m_Idr.PutId(resid); } } diff --git a/DVServerKMD/viogpulite.h b/DVServerKMD/viogpulite.h index 9298088..52a6eec 100644 --- a/DVServerKMD/viogpulite.h +++ b/DVServerKMD/viogpulite.h @@ -1,5 +1,5 @@ -/* - * Copyright © 2021 Intel Corporation +/* + * Copyright (C) 2021 Intel Corporation * Copyright (C) 2019-2020 Red Hat, Inc. * * Written By: Vadim Rozenfeld @@ -30,7 +30,13 @@ #pragma once +#include "edid.h" +#include "viogpu.h" #include "helper.h" + +extern "C" { +#include "..\EDIDParser\edidshared.h" +} #pragma pack(push) #pragma pack(1) @@ -72,6 +78,36 @@ typedef struct _CURRENT_MODE } FrameBuffer; } CURRENT_MODE; +class ScreenInfo { +public: + PVIDEO_MODE_INFORMATION m_ModeInfo; + ULONG m_ModeCount; + PUSHORT m_ModeNumbers; + USHORT m_CurrentMode; + USHORT m_CustomMode; + BYTE m_EDIDs[EDID_V1_BLOCK_SIZE]; + GPU_DISP_MODE_EXT gpu_disp_mode_ext[MAX_MODELIST_SIZE]; + output_modelist mode_list; + KEVENT m_DisplayInfoEvent; + KEVENT m_EdidEvent; + KEVENT m_FlushEvent; + VioGpuMemSegment m_FrameSegment; + VioGpuObj* m_pFrameBuf; + BOOL m_FlushCount; + +public: + ScreenInfo(); + ~ScreenInfo(); + PVIDEO_MODE_INFORMATION GetModeInfo(UINT idx) { return &m_ModeInfo[idx]; } + ULONG GetModeCount(void) { return m_ModeCount; } + USHORT GetModeNumber(USHORT idx) { return m_ModeNumbers[idx]; } + USHORT GetCurrentModeIndex(void) { return m_CurrentMode; } + void SetCurrentModeIndex(USHORT idx) { m_CurrentMode = idx; } + void SetCustomDisplay(_In_ USHORT xres, _In_ USHORT yres); + void SetVideoModeInfo(UINT Idx, PGPU_DISP_MODE_EXT pModeInfo); + void Reset(); +}; + class IVioGpuAdapterLite { public: IVioGpuAdapterLite(_In_ PVOID pvDevcieContext) { m_pvDeviceContext = pvDevcieContext; m_bEDID = FALSE; } @@ -82,12 +118,6 @@ class IVioGpuAdapterLite { virtual BOOLEAN InterruptRoutine(_In_ ULONG MessageNumber) = 0; virtual VOID DpcRoutine(void) = 0; virtual VOID ResetDevice(void) = 0; - - virtual ULONG GetModeCount(void) = 0; - PVIDEO_MODE_INFORMATION GetModeInfo(UINT idx) { return &m_ModeInfo[idx]; } - USHORT GetModeNumber(USHORT idx) { return m_ModeNumbers[idx]; } - USHORT GetCurrentModeIndex(void) { return m_CurrentMode; } - VOID SetCurrentModeIndex(USHORT idx) { m_CurrentMode = idx; } virtual VOID BlackOutScreen(CURRENT_MODE* pCurrentMod) = 0; virtual NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, _In_ CONST CURRENT_MODE* pModeCur) = 0; virtual NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition, _In_ CONST CURRENT_MODE* pModeCur) = 0; @@ -98,13 +128,8 @@ class IVioGpuAdapterLite { protected: virtual NTSTATUS GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo) = 0; protected: - PVIDEO_MODE_INFORMATION m_ModeInfo; - ULONG m_ModeCount; - PUSHORT m_ModeNumbers; - USHORT m_CurrentMode; - USHORT m_CustomMode; ULONG m_Id; - BYTE m_EDIDs[MAX_CHILDREN][EDID_V1_BLOCK_SIZE]; + ScreenInfo m_screen[MAX_SCAN_OUT]; BOOLEAN m_bEDID; public: PVOID m_pvDeviceContext; @@ -117,7 +142,6 @@ class VioGpuAdapterLite : VioGpuAdapterLite(_In_ PVOID pvDeviceContext); ~VioGpuAdapterLite(void); NTSTATUS SetCurrentModeExt(CURRENT_MODE* pCurrentMode); - ULONG GetModeCount(void) { return m_ModeCount; } NTSTATUS SetPowerState(DEVICE_POWER_STATE DevicePowerState); NTSTATUS HWInit(WDFCMRESLIST pResList, DXGK_DISPLAY_INFORMATION* pDispInfo); NTSTATUS HWClose(void); @@ -125,7 +149,8 @@ class VioGpuAdapterLite : _In_ UINT SrcBytesPerPixel, _In_ LONG SrcPitch, _In_ UINT SrcWidth, - _In_ UINT SrcHeight); + _In_ UINT SrcHeight, + _In_ UINT ScreenNum); VOID BlackOutScreen(CURRENT_MODE* pCurrentMod); BOOLEAN InterruptRoutine(_In_ ULONG MessageNumber); VOID DpcRoutine(void); @@ -140,6 +165,11 @@ class VioGpuAdapterLite : { return m_Flags.HardwareInit; } + UINT32 GetNumScreens() { return m_u32NumScanouts; } + UINT32 GetModeListSize(UINT32 screen_num) { return m_screen[screen_num].mode_list.modelist_size; } + VOID CopyResolution(UINT32 screen_num, struct edid_info* edata); + PVOID GetFbVAddr(UINT32 screen_num) { return m_screen[screen_num].m_FrameSegment.GetFbVAddr(); } + VOID Close(UINT32 screen_num) { m_screen[screen_num].m_FrameSegment.Close(); } private: void SetHardwareInit(BOOLEAN init) @@ -149,21 +179,18 @@ class VioGpuAdapterLite : protected: private: - NTSTATUS VioGpuAdapterLiteInit(DXGK_DISPLAY_INFORMATION* pDispInfo); - void SetVideoModeInfo(UINT Idx, PGPU_DISP_MODE_EXT pModeInfo); + NTSTATUS VioGpuAdapterLiteInit(); void VioGpuAdapterLiteClose(void); NTSTATUS GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo); BOOLEAN AckFeature(UINT64 Feature); - BOOLEAN GetDisplayInfo(void); - void ProcessEdid(void); - BOOLEAN GetEdids(void); - void AddEdidModes(void); + BOOLEAN GetDisplayInfo(UINT32 screen_num); + void ProcessEdid(UINT32 screen_num); + BOOLEAN GetEdids(UINT32 screen_num); + void AddEdidModes(UINT32 screen_num); // Not needed by the DVServerKMD //NTSTATUS UpdateChildStatus(BOOLEAN connect); - void SetCustomDisplay(_In_ USHORT xres, - _In_ USHORT yres); void CreateFrameBufferObj(PVIDEO_MODE_INFORMATION pModeInfo, CURRENT_MODE* pCurrentMode); - void DestroyFrameBufferObj(BOOLEAN bReset); + void DestroyFrameBufferObj(UINT32 screen_num, BOOLEAN bReset); BOOLEAN CreateCursor(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, _In_ CONST CURRENT_MODE* pCurrentMode); void DestroyCursor(void); BOOLEAN GpuObjectAttach(UINT res_id, VioGpuObj* obj, ULONGLONG width, ULONGLONG height); @@ -184,20 +211,16 @@ class VioGpuAdapterLite : CrsrQueue m_CursorQueue; VioGpuBuf m_GpuBuf; VioGpuIdr m_Idr; - VioGpuObj* m_pFrameBuf; VioGpuObj* m_pCursorBuf; VioGpuMemSegment m_CursorSegment; volatile ULONG m_PendingWorks; KEVENT m_ConfigUpdateEvent; - KEVENT m_DisplayInfoEvent; - KEVENT m_EdidEvent; - KEVENT m_FlushEvent; + PETHREAD m_pWorkThread; BOOLEAN m_bStopWorkThread; CURRENT_MODE m_CurrentModeInfo; BOOLEAN m_bBlobSupported; public: - VioGpuMemSegment m_FrameSegment; PBYTE GetEdidData(UINT Idx); }; diff --git a/DVServerUMD/Common/debug.h b/DVServerUMD/Common/debug.h index 90ff8b2..c0826d0 100644 --- a/DVServerUMD/Common/debug.h +++ b/DVServerUMD/Common/debug.h @@ -1,3 +1,12 @@ +/*=========================================================================== +; debug.h +;---------------------------------------------------------------------------- +; Copyright (C) 2021 Intel Corporation +; SPDX-License-Identifier: MS-PL +; +; File Description: +; This file declares and defines the devserverumd logging macros +;--------------------------------------------------------------------------*/ #ifndef _DEBUG_H #define _DEBUG_H @@ -32,6 +41,7 @@ static char module_name[80] = { '\0' }; sprintf_s(temp_str456, fmt, ##__VA_ARGS__); \ sprintf_s(temp_str789, "%s%s", temp_str123, temp_str456); \ OutputDebugStringA(temp_str789); \ + fflush(stdout); \ } #define _PRINT(prefix, fmt, ...) \ @@ -41,6 +51,7 @@ static char module_name[80] = { '\0' }; sprintf_s(temp_str456, fmt, ##__VA_ARGS__); \ sprintf_s(temp_str789, "%s%s", temp_str123, temp_str456); \ OutputDebugStringA(temp_str789); \ + fflush(stdout); \ } #define PRINT(fmt, ...) _PRINT("", fmt, ##__VA_ARGS__) diff --git a/DVServerUMD/DVEnabler/DVEnabler/DVEnabler.cpp b/DVServerUMD/DVEnabler/DVEnabler/DVEnabler.cpp index fff1a20..43eb8d3 100644 --- a/DVServerUMD/DVEnabler/DVEnabler/DVEnabler.cpp +++ b/DVServerUMD/DVEnabler/DVEnabler/DVEnabler.cpp @@ -1,7 +1,7 @@ -/*=========================================================================== +/*=========================================================================== ; DVEnabler.cpp ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: MIT ; ; File Description: @@ -20,13 +20,16 @@ int main() TRACING(); DISPLAYCONFIG_TARGET_BASE_TYPE baseType; - unsigned int mode_index = 0; unsigned int path_count = 0, mode_count = 0; bool found_id_path = false, found_non_id_path = false; + char err[256]; + memset(err, 0, 256); /* Step 0: Get the size of buffers w.r.t active paths and modes, required for QueryDisplayConfig */ if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &path_count, &mode_count) != ERROR_SUCCESS) { - ERR("GetDisplayConfigBufferSizes failed... Exiting!!!\n"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL); + ERR("GetDisplayConfigBufferSizes failed with %s. Exiting!!!\n", err); return -1; } @@ -36,7 +39,9 @@ int main() /* Step 1: Retrieve information about all possible display paths for all display devices */ if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &path_count, path_list.data(), &mode_count, mode_list.data(), nullptr) != ERROR_SUCCESS) { - ERR("QueryDisplayConfig failed... Exiting!!!\n"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL); + ERR("QueryDisplayConfig failed with %s. Exiting!!!\n", err); return -1; } @@ -52,22 +57,25 @@ int main() continue; } - /* Step 3: Check for the "outputTechnology" it should be "DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED" for - IDD path ONLY, In case of MSFT display we need to disable the active display path */ - if (baseType.baseOutputTechnology != DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED) { - - /* Step 4: Clear the DISPLAYCONFIG_PATH_INFO.flags for MSFT path*/ - activepath_loopindex.flags = 0; - DBGPRINT("Clearing Microsoft activepath_loopindex.flags\n"); - found_non_id_path = true; - } - else { - found_id_path = true; - /* Move the IDD source co-ordinates to (0,0) */ - mode_list[activepath_loopindex.sourceInfo.modeInfoIdx].sourceMode.position.x = 0; - mode_list[activepath_loopindex.sourceInfo.modeInfoIdx].sourceMode.position.y = 0; + DBGPRINT("baseType.baseOutputTechnology = %d\n", baseType.baseOutputTechnology); + if (!(found_non_id_path && found_id_path)) { + /* Step 3: Check for the "outputTechnology" it should be "DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED" for + IDD path ONLY, In case of MSFT display we need to disable the active display path */ + if (baseType.baseOutputTechnology != DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED) { + + /* Step 4: Clear the DISPLAYCONFIG_PATH_INFO.flags for MSFT path*/ + activepath_loopindex.flags = 0; + DBGPRINT("Clearing Microsoft activepath_loopindex.flags.\n"); + found_non_id_path = true; + } else { + found_id_path = true; + /* Move the IDD source co-ordinates to (0,0) */ + mode_list[activepath_loopindex.sourceInfo.modeInfoIdx].sourceMode.position.x = 0; + mode_list[activepath_loopindex.sourceInfo.modeInfoIdx].sourceMode.position.y = 0; + DBGPRINT("x, y = %dX%x\n", mode_list[activepath_loopindex.sourceInfo.modeInfoIdx].sourceMode.position.x, + mode_list[activepath_loopindex.sourceInfo.modeInfoIdx].sourceMode.position.y); + } } - mode_index = mode_index + 2; } if (found_non_id_path && found_id_path) { @@ -75,11 +83,14 @@ int main() paths in the current session. */ if (SetDisplayConfig(path_count, path_list.data(), mode_count, mode_list.data(), \ SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_SAVE_TO_DATABASE) != ERROR_SUCCESS) { - ERR("SetDisplayConfig failed\n"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL); + ERR("SetDisplayConfig failed with %s\n", err); + return -1; } - } - else { - DBGPRINT("Skipping SetDisplayConfig as did not find ID and non-ID path\n"); + } else { + INFO("Skipping SetDisplayConfig as did not find ID and non-ID path. found_non_id_path = %d, found_id_path = %d\n", + found_non_id_path, found_id_path); } return 0; diff --git a/DVServerUMD/DVEnabler/DVEnabler/DVEnabler.vcxproj b/DVServerUMD/DVEnabler/DVEnabler/DVEnabler.vcxproj index e13577b..cc6b8c2 100644 --- a/DVServerUMD/DVEnabler/DVEnabler/DVEnabler.vcxproj +++ b/DVServerUMD/DVEnabler/DVEnabler/DVEnabler.vcxproj @@ -116,7 +116,7 @@ Level3 true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + __DEBUG;_CONSOLE;%(PreprocessorDefinitions) true MultiThreadedDebug ..\..\Common diff --git a/DVServerUMD/DVServer/DVServer.vcxproj b/DVServerUMD/DVServer/DVServer.vcxproj index a6feaca..07f742a 100644 --- a/DVServerUMD/DVServer/DVServer.vcxproj +++ b/DVServerUMD/DVServer/DVServer.vcxproj @@ -37,6 +37,7 @@ + diff --git a/DVServerUMD/DVServer/DVServerUMD_Version.txt b/DVServerUMD/DVServer/DVServerUMD_Version.txt index 4eefd2d..c273d73 100644 --- a/DVServerUMD/DVServer/DVServerUMD_Version.txt +++ b/DVServerUMD/DVServer/DVServerUMD_Version.txt @@ -1,7 +1,7 @@ /*=========================================================================== ; DVServerUMD_Version.txt ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: MS-PL ; ; File Description: diff --git a/DVServerUMD/DVServer/DVServercommon.h b/DVServerUMD/DVServer/DVServercommon.h index d162af8..b84248c 100644 --- a/DVServerUMD/DVServer/DVServercommon.h +++ b/DVServerUMD/DVServer/DVServercommon.h @@ -1,7 +1,7 @@ /*=========================================================================== ; DVServercommon.h ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: MS-PL ; ; File Description: @@ -15,5 +15,12 @@ /* DVServerUMD Error Codes */ #define DVSERVERUMD_SUCCESS 0 #define DVSERVERUMD_FAILURE -1 +#define MAX_REG_NAME_LENGTH 32 +#define EDID_SIZE 256 + +static NTSTATUS open_dvserver_registry(WDFKEY * key); +static void close_dvserver_registry(WDFKEY key); +int write_dvserver_registry_binary(PCWSTR name, BYTE * buffer, ULONG size); +int read_dvserver_registry_binary(PCWSTR name, BYTE * buffer, ULONG * size); #endif /* __DVSERVER_COMMON_H__ */ diff --git a/DVServerUMD/DVServer/DVServeredid.cpp b/DVServerUMD/DVServer/DVServeredid.cpp index bbc78a4..e2ed758 100644 --- a/DVServerUMD/DVServer/DVServeredid.cpp +++ b/DVServerUMD/DVServer/DVServeredid.cpp @@ -1,7 +1,7 @@ -/*=========================================================================== +/*=========================================================================== ; DVServeredid.cpp ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: MS-PL ; ; File Description: @@ -12,62 +12,13 @@ #include using namespace Microsoft::IndirectDisp; -extern struct IndirectSampleMonitor s_SampleMonitors[]; PSP_DEVICE_INTERFACE_DETAIL_DATA device_iface_edid_data; +struct edid_info* edata = NULL; +struct screen_info* mdata = NULL; +ULONG bytesReturned = 0; unsigned int blacklisted_resolution_list[][2] = { {1400,1050} }; // blacklisted resolution can be appended here - -/******************************************************************************* -* -* Description -* -* get_dvserver_edid_kmdf_device - This function checks for the DVserverKMD edid -* device node created and opens a handle for DVServerUMD to use -* -* Parameters -* Null -* -* Return val -* int - 0 == SUCCESS, -1 = ERROR -* -******************************************************************************/ -int get_dvserver_edid_kmdf_device(void) -{ - TRACING(); - HDEVINFO devinfo_edid_handle = NULL; - DWORD sizeof_deviceinterface_buf = 0; - BOOL ret = FALSE; - SP_DEVICE_INTERFACE_DATA device_interface_data; - - device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - devinfo_edid_handle = SetupDiGetClassDevs(NULL, NULL, NULL, DEVINFO_FLAGS); - - ret = SetupDiEnumDeviceInterfaces(devinfo_edid_handle, 0, &GUID_DEVINTERFACE_DVSERVERKMD, 0, &device_interface_data); - if (ret == FALSE) { - ERR("SetupDiEnumDeviceInterfaces failed\n"); - return DVSERVERUMD_FAILURE; - } - - SetupDiGetDeviceInterfaceDetail(devinfo_edid_handle, &device_interface_data, 0, 0, &sizeof_deviceinterface_buf, 0); - if (sizeof_deviceinterface_buf == 0) { - ERR("SetupDiGetDeviceInterfaceDetail failed\n"); - return DVSERVERUMD_FAILURE; - } - - device_iface_edid_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(sizeof_deviceinterface_buf); - if (device_iface_edid_data == NULL) { - ERR("Failed allocating memory for device interface data\n"); - return DVSERVERUMD_FAILURE; - } - - device_iface_edid_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - ret = SetupDiGetDeviceInterfaceDetail(devinfo_edid_handle, &device_interface_data, device_iface_edid_data, sizeof_deviceinterface_buf, 0, 0); - if (ret == FALSE) { - ERR("SetupDiGetDeviceInterfaceDetail Failed\n"); - return DVSERVERUMD_FAILURE; - } - return DVSERVERUMD_SUCCESS; -} +char* screenedid[MAX_SCAN_OUT] = { "ScreenEDID1", "ScreenEDID2", "ScreenEDID3", "ScreenEDID4" }; /******************************************************************************* * @@ -77,44 +28,41 @@ int get_dvserver_edid_kmdf_device(void) * and send an ioctl(IOCTL_DVSERVER_GET_EDID_DATA)to DVserverKMD to get edid data * * Parameters -* Null +* Device frame Handle to DVServerKMD +* pointer to IndirectSampleMonitor structure +* Screen ID * * Return val * int - 0 == SUCCESS, -1 = ERROR * ******************************************************************************/ -int get_edid_data(void) +int get_edid_data(HANDLE devHandle, void *m, DWORD id) { TRACING(); unsigned int i= 0, edid_mode_index = 0; - HANDLE devHandle_edid; - struct edid_info* edata = NULL; - ULONG bytesReturned = 0; + IndirectSampleMonitor* monitor = (IndirectSampleMonitor *) m; - if (get_dvserver_edid_kmdf_device() == -1) { - ERR("KMD resource Init Failed\n"); + if (!m) { + ERR("Invalid parameter\n"); return DVSERVERUMD_FAILURE; } - devHandle_edid = CreateFile(device_iface_edid_data->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0); - if (devHandle_edid == INVALID_HANDLE_VALUE) { - ERR("CreateFile for EDID returned INVALID_HANDLE_VALUE\n"); - return DVSERVERUMD_FAILURE; - } + BYTE regedid[EDID_SIZE] = { 0 }; + ULONG buff_size = EDID_SIZE; + size_t requiredSize = 0; + int status = 0; edata = (struct edid_info*)malloc(sizeof(struct edid_info)); if (edata == NULL) { ERR("Failed to allocate edid structure\n"); - CloseHandle(devHandle_edid); return DVSERVERUMD_FAILURE; } SecureZeroMemory(edata, sizeof(struct edid_info)); DBGPRINT("Requesting Mode List size through EDID IOCTL\n"); - if (!DeviceIoControl(devHandle_edid, IOCTL_DVSERVER_GET_EDID_DATA, edata, sizeof(struct edid_info), edata, sizeof(struct edid_info), &bytesReturned, NULL)) { + if (!DeviceIoControl(devHandle, IOCTL_DVSERVER_GET_EDID_DATA, edata, sizeof(struct edid_info), edata, sizeof(struct edid_info), &bytesReturned, NULL)) { ERR("IOCTL_DVSERVER_GET_EDID_DATA call failed\n"); free(edata); - CloseHandle(devHandle_edid); return DVSERVERUMD_FAILURE; } @@ -122,40 +70,106 @@ int get_edid_data(void) if (edata->mode_list == NULL) { ERR("Failed to allocate mode list structure\n"); free(edata); - CloseHandle(devHandle_edid); return DVSERVERUMD_FAILURE; } SecureZeroMemory(edata->mode_list, sizeof(struct mode_info) * edata->mode_size); DBGPRINT("Requesting EDID Data through EDID IOCTL\n"); - if (!DeviceIoControl(devHandle_edid, IOCTL_DVSERVER_GET_EDID_DATA, edata, sizeof(struct edid_info), edata, sizeof(struct edid_info), &bytesReturned, NULL)) { + if (!DeviceIoControl(devHandle, IOCTL_DVSERVER_GET_EDID_DATA, edata, sizeof(struct edid_info), edata, sizeof(struct edid_info), &bytesReturned, NULL)) { ERR("IOCTL_DVSERVER_GET_EDID_DATA call failed!\n"); free(edata->mode_list); free(edata); - CloseHandle(devHandle_edid); return DVSERVERUMD_FAILURE; } - memcpy_s(s_SampleMonitors[0].pEdidBlock, s_SampleMonitors->szEdidBlock, edata->edid_data, s_SampleMonitors->szEdidBlock); + wchar_t* Lscreenedid = new wchar_t[strlen(screenedid[id]) + 1]; + mbstowcs_s(&requiredSize, Lscreenedid, strlen(screenedid[id]) + 1, screenedid[id], strlen(screenedid[id])); + if (requiredSize != 0) { + DBGPRINT("Screen EDID regkey = %ls", Lscreenedid); + status = read_dvserver_registry_binary(Lscreenedid, regedid, &buff_size); + + if (status != DVSERVERUMD_SUCCESS) { + DBGPRINT("idd_read_registry_binary Failed, EDID received from KMD will be used"); + write_dvserver_registry_binary(Lscreenedid, edata->edid_data, EDID_SIZE); + memcpy_s(monitor->pEdidBlock, monitor->szEdidBlock, edata->edid_data, monitor->szEdidBlock); + } + else { + DBGPRINT("idd_read_registry_binary Passed, EDID from local registry will be used"); + memcpy_s(monitor->pEdidBlock, monitor->szEdidBlock, regedid, monitor->szEdidBlock); + } + } + delete[] Lscreenedid; - for (i=0; i< edata->mode_size; i++) { + monitor->ulPreferredModeIdx = 0; + + DBGPRINT("Modes\n"); + for (i = 0; i < edata->mode_size; i++) { //TRIMMING LOGIC: Restricting EDID size to 32 and discarding modes with width more than 3840 & less than 1024 - if ((edata->mode_list[i].width <= WIDTH_UPPER_CAP) && (edata->mode_list[i].width >= WIDTH_LOWER_CAP) && (edid_mode_index < s_SampleMonitors->szModeList) && (is_blacklist(edata->mode_list[i].width, edata->mode_list[i].height) == 0)) { - s_SampleMonitors[0].pModeList[edid_mode_index].Width = edata->mode_list[i].width; - s_SampleMonitors[0].pModeList[edid_mode_index].Height = edata->mode_list[i].height; + if ((edata->mode_list[i].width <= WIDTH_UPPER_CAP) && + (edata->mode_list[i].width >= WIDTH_LOWER_CAP) && + (edid_mode_index < monitor->szModeList) && + (is_blacklist(edata->mode_list[i].width, edata->mode_list[i].height) == 0)) { + monitor->pModeList[edid_mode_index].Width = edata->mode_list[i].width; + monitor->pModeList[edid_mode_index].Height = edata->mode_list[i].height; if ((DWORD)edata->mode_list[i].refreshrate == REFRESH_RATE_59) - s_SampleMonitors[0].pModeList[edid_mode_index].VSync = REFRESH_RATE_60; + monitor->pModeList[edid_mode_index].VSync = REFRESH_RATE_60; else - s_SampleMonitors[0].pModeList[edid_mode_index].VSync = (DWORD)edata->mode_list[i].refreshrate; + monitor->pModeList[edid_mode_index].VSync = (DWORD)edata->mode_list[i].refreshrate; + DBGPRINT("[%d]: %dx%d@%d\n", edid_mode_index, + monitor->pModeList[edid_mode_index].Width, monitor->pModeList[edid_mode_index].Height, + monitor->pModeList[edid_mode_index].VSync); edid_mode_index++; } } free(edata->mode_list); free(edata); - CloseHandle(devHandle_edid); return DVSERVERUMD_SUCCESS; } +/******************************************************************************* +* +* Description +* +* get_total_screens - This function sends an ioctl(IOCTL_DVSERVER_GET_TOTAL_SCREENS) +* to DVserverKMD to get the total number of screens +* +* Parameters +* Device frame Handle to DVServerKMD +* +* Return val +* int - -1 = ERROR, any other value = number of total screens connected +* +******************************************************************************/ +int get_total_screens(HANDLE devHandle) +{ + TRACING(); + int ret = DVSERVERUMD_FAILURE; + + if (!devHandle) { + ERR("Invalid devHandle\n"); + return ret; + } + + mdata = (struct screen_info*)malloc(sizeof(struct screen_info)); + if (mdata == NULL) { + ERR("Failed to allocate Screen structure\n"); + return ret; + } + SecureZeroMemory(mdata, sizeof(struct screen_info)); + + DBGPRINT("Requesting Screen Count through Screen IOCTL\n"); + if (!DeviceIoControl(devHandle, IOCTL_DVSERVER_GET_TOTAL_SCREENS, mdata, sizeof(struct screen_info), mdata, sizeof(struct screen_info), &bytesReturned, NULL)) { + ERR("IOCTL_DVSERVER_GET_TOTAL_SCREENS call failed\n"); + free(mdata); + return ret; + } + + DBGPRINT("Total screens = %d\n", mdata->total_screens); + ret = mdata->total_screens; + free(mdata); + return ret; +} + /******************************************************************************* * * Description @@ -172,8 +186,8 @@ int get_edid_data(void) * int - 0 == SUCCESS, -1 = ERROR * ******************************************************************************/ -int is_blacklist(unsigned int width, unsigned int height) { - TRACING(); +int is_blacklist(unsigned int width, unsigned int height) +{ unsigned int i = 0; for (i = 0; i < ARRAY_SIZE(blacklisted_resolution_list); i++) { @@ -182,4 +196,4 @@ int is_blacklist(unsigned int width, unsigned int height) { } } return DVSERVERUMD_SUCCESS; -} \ No newline at end of file +} diff --git a/DVServerUMD/DVServer/DVServeredid.h b/DVServerUMD/DVServer/DVServeredid.h index 16badac..12b83e4 100644 --- a/DVServerUMD/DVServer/DVServeredid.h +++ b/DVServerUMD/DVServer/DVServeredid.h @@ -1,7 +1,7 @@ /*=========================================================================== ; DVServeredid.h ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: MS-PL ; ; File Description: @@ -28,8 +28,8 @@ #define REFRESH_RATE_60 60 //60Hz #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) -int get_dvserver_edid_kmdf_device(void); -int get_edid_data(void); +int get_total_screens(HANDLE devHandle); +int get_edid_data(HANDLE devHandle, void *m, DWORD id); int is_blacklist(unsigned int width, unsigned int height); #endif /* __DVSERVER_EDID_H__ */ diff --git a/DVServerUMD/DVServer/DVServerregistry.cpp b/DVServerUMD/DVServer/DVServerregistry.cpp new file mode 100644 index 0000000..bdc57d5 --- /dev/null +++ b/DVServerUMD/DVServer/DVServerregistry.cpp @@ -0,0 +1,160 @@ +/*=========================================================================== +; DVServerregistry.cpp +;---------------------------------------------------------------------------- +; Copyright (C) 2021 Intel Corporation +; SPDX-License-Identifier: MS-PL +; +; File Description: +; This file has utility API which reads & writes windows registry key +;--------------------------------------------------------------------------*/ + +#include "DVServercommon.h" +#include "debug.h" + +extern WDFDEVICE g_dvserver_device; + +/*--------------------------------------------------------------------------- +* +*Description +* +* open_dvserver_registry - This function helps to open the ServiceName subkey of the +* driver's software key for read/write access +* +* Parameters +* Null +* +* Return val +* int - 0 == SUCCESS, Non-Zero = ERROR +* +*--------------------------------------------------------------------------*/ +static NTSTATUS open_dvserver_registry(WDFKEY* key) +{ + TRACING(); + NTSTATUS status = STATUS_SUCCESS; + + if (!key) { + return STATUS_UNSUCCESSFUL; + } + + status = WdfDeviceOpenRegistryKey( + g_dvserver_device, + PLUGPLAY_REGKEY_DRIVER | WDF_REGKEY_DRIVER_SUBKEY, + KEY_READ | KEY_SET_VALUE, + WDF_NO_OBJECT_ATTRIBUTES, + key); + DBGPRINT("WdfDeviceOpenRegistryKey status: %x", status); + return status; +} + + +/*--------------------------------------------------------------------------- +* +*Description +* +* close_dvserver_registry - This function helps to close driver's registry key +* +* Parameters +* Null +* +* Return val +* void +* +*--------------------------------------------------------------------------*/ +static void close_dvserver_registry(WDFKEY key) +{ + TRACING(); + WdfRegistryClose(key); +} + + +/*--------------------------------------------------------------------------- +* +*Description +* +* write_dvserver_registry_binary - This function helps to write binary data +* from a buffer into registry +* +* Parameters +* Null +* +* Return val +* int - 0 == SUCCESS, -1 = ERROR +* +*--------------------------------------------------------------------------*/ +int write_dvserver_registry_binary(PCWSTR name, BYTE* buffer, ULONG size) +{ + TRACING(); + NTSTATUS status = STATUS_SUCCESS; + WDFKEY key_idd; + UNICODE_STRING uc_name; + ULONG value_type = REG_BINARY; + + if (!name || !buffer || !size) { + return DVSERVERUMD_FAILURE; + } + + status = open_dvserver_registry(&key_idd); + + if (NT_SUCCESS(status)) { + RtlInitUnicodeString(&uc_name, name); + status = WdfRegistryAssignValue( + key_idd, + &uc_name, + value_type, + size, + buffer); + DBGPRINT("WdfRegistryAssignValue return status: %x", status); + close_dvserver_registry(key_idd); + if (NT_SUCCESS(status)) { + return DVSERVERUMD_SUCCESS; + } + } + return DVSERVERUMD_FAILURE; +} + +/*--------------------------------------------------------------------------- +* +*Description +* +* read_dvserver_registry_binary - This function helps to to read binary data +* from registry into a buffer +* +* Parameters +* Null +* +* Return val +* int - 0 == SUCCESS, -1 = ERROR +* +*--------------------------------------------------------------------------*/ +int read_dvserver_registry_binary(PCWSTR name, BYTE* buffer, ULONG* size) +{ + TRACING(); + NTSTATUS status = STATUS_SUCCESS; + WDFKEY key_idd; + UNICODE_STRING uc_name; + ULONG value_len, value_type = REG_BINARY; + + if (!name || !buffer || !size) { + return DVSERVERUMD_FAILURE; + } + + status = open_dvserver_registry(&key_idd); + + if (NT_SUCCESS(status)) { + RtlInitUnicodeString(&uc_name, name); + status = WdfRegistryQueryValue( + key_idd, + &uc_name, + *size, + buffer, + &value_len, + &value_type); + DBGPRINT("WdfRegistryQueryValue return status: %x, read length: %d", status, value_len); + close_dvserver_registry(key_idd); + if (NT_SUCCESS(status)) { + *size = value_len; + return DVSERVERUMD_SUCCESS; + } + } + return DVSERVERUMD_FAILURE; +} \ No newline at end of file diff --git a/DVServerUMD/DVServer/Driver.cpp b/DVServerUMD/DVServer/Driver.cpp index bf36f49..ee5f6dc 100644 --- a/DVServerUMD/DVServer/Driver.cpp +++ b/DVServerUMD/DVServer/Driver.cpp @@ -30,19 +30,19 @@ Copyright (c) Microsoft Corporation #pragma comment (lib, "Setupapi.lib") -//DVServer KMD related -PSP_DEVICE_INTERFACE_DETAIL_DATA device_iface_data; -HDEVINFO devinfo_handle; -HANDLE devHandle_frame; -BOOL g_init_kmd_resources = TRUE; - using namespace std; using namespace Microsoft::IndirectDisp; using namespace Microsoft::WRL; +//DVServer KMD related +DeviceInfo* g_DevInfo; +UINT g_DevInfoCounter = 0; +BOOL g_init_kmd_resources = TRUE; + #pragma region SampleMonitors -static constexpr DWORD IDD_SAMPLE_MONITOR_COUNT = 1; // If monitor count > ARRAYSIZE(s_SampleMonitors), we create edid-less monitors +DWORD idd_monitor_count = 1; +IndirectSampleMonitor* g_monitors = NULL; // Default modes reported for edid-less monitors. The first mode is set as preferred static const struct IndirectSampleMonitor::SampleMonitorMode s_SampleDefaultModes[] = @@ -68,47 +68,6 @@ HANDLE devHandle_cursor; #endif //end of DVSERVER_HWDCURSOR -// FOR SAMPLE PURPOSES ONLY, Static info about monitors that will be reported to OS -struct IndirectSampleMonitor s_SampleMonitors[] = -{ - // Modified EDID from Dell S2719DGF - { - { - 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x10,0xAC,0xE6,0xD0,0x55,0x5A,0x4A,0x30,0x24,0x1D,0x01, - 0x04,0xA5,0x3C,0x22,0x78,0xFB,0x6C,0xE5,0xA5,0x55,0x50,0xA0,0x23,0x0B,0x50,0x54,0x00,0x02,0x00, - 0xD1,0xC0,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x58,0xE3,0x00, - 0xA0,0xA0,0xA0,0x29,0x50,0x30,0x20,0x35,0x00,0x55,0x50,0x21,0x00,0x00,0x1A,0x00,0x00,0x00,0xFF, - 0x00,0x37,0x4A,0x51,0x58,0x42,0x59,0x32,0x0A,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,0x00, - 0x53,0x32,0x37,0x31,0x39,0x44,0x47,0x46,0x0A,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFD,0x00,0x28, - 0x9B,0xFA,0xFA,0x40,0x01,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x2C - }, - { - { 1024, 768, 60 }, - { 1600, 1200, 60 }, - { 1920, 1080, 60 }, - }, - 0 - }, - // Modified EDID from Lenovo Y27fA - { - { - 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x30,0xAE,0xBF,0x65,0x01,0x01,0x01,0x01,0x20,0x1A,0x01, - 0x04,0xA5,0x3C,0x22,0x78,0x3B,0xEE,0xD1,0xA5,0x55,0x48,0x9B,0x26,0x12,0x50,0x54,0x00,0x08,0x00, - 0xA9,0xC0,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x68,0xD8,0x00, - 0x18,0xF1,0x70,0x2D,0x80,0x58,0x2C,0x45,0x00,0x53,0x50,0x21,0x00,0x00,0x1E,0x00,0x00,0x00,0x10, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFD,0x00, - 0x30,0x92,0xB4,0xB4,0x22,0x01,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,0x00,0x4C, - 0x45,0x4E,0x20,0x59,0x32,0x37,0x66,0x41,0x0A,0x20,0x20,0x20,0x00,0x11 - }, - { - { 3840, 2160, 60 }, - { 1600, 900, 60 }, - { 1024, 768, 60 }, - }, - 0 - } -}; - #pragma endregion #pragma region helpers @@ -170,6 +129,8 @@ EVT_IDD_CX_MONITOR_QUERY_TARGET_MODES IddSampleMonitorQueryModes; EVT_IDD_CX_MONITOR_ASSIGN_SWAPCHAIN IddSampleMonitorAssignSwapChain; EVT_IDD_CX_MONITOR_UNASSIGN_SWAPCHAIN IddSampleMonitorUnassignSwapChain; +WDFDEVICE g_dvserver_device = NULL; + struct IndirectDeviceContextWrapper { IndirectDeviceContext* pContext; @@ -178,6 +139,11 @@ struct IndirectDeviceContextWrapper { delete pContext; pContext = nullptr; + + if (g_DevInfo) { + delete g_DevInfo; + g_DevInfo = nullptr; + } } }; @@ -217,7 +183,7 @@ extern "C" NTSTATUS DriverEntry( { WDF_DRIVER_CONFIG Config; NTSTATUS Status; - set_module_name("DVServerUMD"); + set_module_name("UMD"); TRACING(); WDF_OBJECT_ATTRIBUTES Attributes; @@ -239,6 +205,7 @@ extern "C" NTSTATUS DriverEntry( _Use_decl_annotations_ NTSTATUS IddSampleDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT pDeviceInit) { + DWORD count = 0; NTSTATUS Status = STATUS_SUCCESS; WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks; @@ -292,14 +259,27 @@ NTSTATUS IddSampleDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT pDeviceInit) } Status = IddCxDeviceInitialize(Device); + g_dvserver_device = Device; // Create a new device context object and attach it to the WDF device object auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(Device); pContext->pContext = new IndirectDeviceContext(Device); - - if (get_edid_data() == DVSERVERUMD_FAILURE) { - ERR("QEMU EDID initialization failed, falling back to default IDD EDID"); - } + + g_DevInfo = new DeviceInfo(); + + idd_monitor_count = get_total_screens(g_DevInfo->get_Handle()); + if (idd_monitor_count == DVSERVERUMD_FAILURE) { + ERR("Failed to get total screens from KMD"); + return DVSERVERUMD_FAILURE; + } + + g_monitors = new IndirectSampleMonitor[idd_monitor_count]; + for (count = 0; count < idd_monitor_count; count++) { + if (get_edid_data(g_DevInfo->get_Handle(), &g_monitors[count], count) == DVSERVERUMD_FAILURE) { + ERR("Failed to get EDID from QEMU"); + return DVSERVERUMD_FAILURE; + } + } return Status; } @@ -365,30 +345,110 @@ HRESULT Direct3DDevice::Init() #pragma endregion +#pragma region DeviceInfo + +DeviceInfo::DeviceInfo() +{ + devHandle_frame = NULL; + if (get_dvserver_kmdf_device() == DVSERVERUMD_FAILURE) { + ERR("KMD resource Init Failed\n"); + return; + } + // ****** Frame Resources ****** + //Create Device frame Handle to DVServerKMD + devHandle_frame = CreateFile(device_iface_data->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0); + if (devHandle_frame == INVALID_HANDLE_VALUE) { + ERR("CreateFile for Frame returned INVALID_HANDLE_VALUE\n"); + return; + } +} + +DeviceInfo::~DeviceInfo() +{ + if (devHandle_frame != INVALID_HANDLE_VALUE) { + CloseHandle(devHandle_frame); + devHandle_frame = INVALID_HANDLE_VALUE; + } + + if (device_iface_data) { + free(device_iface_data); + device_iface_data = NULL; + } + + if (devinfo_handle != INVALID_HANDLE_VALUE) { + SetupDiDestroyDeviceInfoList(devinfo_handle); + devinfo_handle = INVALID_HANDLE_VALUE; + } +} + +/******************************************************************************* +* +* Description +* +* get_dvserver_kmdf_device - This function checks for the DVserverKMD device +* created and opens a handle for DVserverUMD to use +* +* Parameters +* Null +* +* Return val +* int - 0 == SUCCESS, -1 = ERROR +* +******************************************************************************/ +int DeviceInfo::get_dvserver_kmdf_device() +{ + DWORD sizeof_deviceinterface_buf = 0; + BOOL ret; + SP_DEVICE_INTERFACE_DATA device_interface_data; + TRACING(); + + device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + devinfo_handle = SetupDiGetClassDevs(NULL, NULL, NULL, DEVINFO_FLAGS); + + ret = SetupDiEnumDeviceInterfaces(devinfo_handle, 0, &GUID_DEVINTERFACE_DVSERVERKMD, 0, &device_interface_data); + if (ret == FALSE) { + ERR("SetupDiEnumDeviceInterfaces failed\n"); + return DVSERVERUMD_FAILURE; + } + + SetupDiGetDeviceInterfaceDetail(devinfo_handle, &device_interface_data, 0, 0, &sizeof_deviceinterface_buf, 0); + if (sizeof_deviceinterface_buf == 0) { + ERR("SetupDiGetDeviceInterfaceDetail failed\n"); + return DVSERVERUMD_FAILURE; + } + + device_iface_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(sizeof_deviceinterface_buf); + if (device_iface_data == NULL) { + ERR("Failed allocating memory for device interface data\n"); + return DVSERVERUMD_FAILURE; + } + + device_iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + ret = SetupDiGetDeviceInterfaceDetail(devinfo_handle, &device_interface_data, device_iface_data, sizeof_deviceinterface_buf, 0, 0); + if (ret == FALSE) { + ERR("etupDiGetDeviceInterfaceDetail Failed\nn"); + free(device_iface_data); + device_iface_data = NULL; + return DVSERVERUMD_FAILURE; + } + + return DVSERVERUMD_SUCCESS; +} + +#pragma endregion + #pragma region SwapChainProcessor -SwapChainProcessor::SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, shared_ptr Device, HANDLE NewFrameEvent) - : m_hSwapChain(hSwapChain), m_Device(Device), m_hAvailableBufferEvent(NewFrameEvent) +SwapChainProcessor::SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, shared_ptr Device, HANDLE NewFrameEvent, UINT MonitorIndex) + : m_hSwapChain(hSwapChain), m_Device(Device), m_hAvailableBufferEvent(NewFrameEvent), m_screen_num(0), print_counter(0) { init(); TRACING(); m_hTerminateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr)); - if (get_dvserver_kmdf_device() == DVSERVERUMD_FAILURE) { - ERR("KMD resource Init Failed\n"); - goto exit; - } - // ****** Frame Resources ****** - //Create Device frame Handle to DVServerKMD - devHandle_frame = CreateFile(device_iface_data->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0); - if (devHandle_frame == INVALID_HANDLE_VALUE) { - ERR("CreateFile for Frame returned INVALID_HANDLE_VALUE\n"); - goto exit; - } - - //Allocate memory for IOCTL Response Buffer from DVServerKMD (for frame) + //Allocate memory for IOCTL Response Buffer from DVServerKMD (for frame) m_ioctlresp_frame = (struct KMDF_IOCTL_Response*)malloc(sizeof(struct KMDF_IOCTL_Response)); if (m_ioctlresp_frame == NULL) { ERR("Failed allocating IOCTL Response structure (for frame)\n"); @@ -408,6 +468,9 @@ SwapChainProcessor::SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, shared_ptr DxgiDevice; HRESULT status; + char err[256]; + memset(err, 0, 256); TRACING(); HRESULT hr = m_Device->Device.As(&DxgiDevice); @@ -621,7 +676,9 @@ void SwapChainProcessor::RunCore() hr = IddCxSwapChainSetDevice(m_hSwapChain, &SetDevice); if (FAILED(hr)) { - ERR("IddCxSwapChainSetDevice failed\n"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL); + ERR("IddCxSwapChainSetDevice failed, screen = %d, err = %s\n", m_screen_num, err); return; } @@ -650,7 +707,7 @@ void SwapChainProcessor::RunCore() if (WaitResult == WAIT_OBJECT_0 || WaitResult == WAIT_TIMEOUT) { // We have a new buffer, so try the AcquireBuffer again - INFO("New buffer, so trying the AcquireBuffer again\n"); + DBGPRINT("New buffer, so trying the AcquireBuffer again\n"); continue; } else if (WaitResult == WAIT_OBJECT_0 + 1) @@ -663,7 +720,9 @@ void SwapChainProcessor::RunCore() { // The wait was cancelled or something unexpected happened hr = HRESULT_FROM_WIN32(WaitResult); - ERR("Wait was either cancelled or something unexpected happened\n"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL); + ERR("Wait was either cancelled or something unexpected happened, screen = %d, err = %s\n", m_screen_num, err); break; } } @@ -683,6 +742,7 @@ void SwapChainProcessor::RunCore() //Get Frame from GPU if (GetFrameData(m_Device, m_IAcquiredDesktopImage) == DVSERVERUMD_FAILURE) { ERR("Failed getting frame from GPU\n"); + AcquiredBuffer.Reset(); //We need to reset the swapchain in case of any catastrophic failures or any kind of TDR in GFX driver //so exiting the runcore, OS will restart the IDD display break; @@ -695,7 +755,9 @@ void SwapChainProcessor::RunCore() hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain); if (FAILED(hr)) { - ERR("IddCxSwapChainFinishedProcessingFrame Failed\n"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL); + ERR("IddCxSwapChainFinishedProcessingFrame Failed, screen = %d, err = %s\n", m_screen_num, err); break; } @@ -710,7 +772,9 @@ void SwapChainProcessor::RunCore() else { // The swap-chain was likely abandoned (e.g. DXGI_ERROR_ACCESS_LOST), so exit the processing loop - ERR("The swap-chain was likely abandoned (e.g. DXGI_ERROR_ACCESS_LOST), so exiting\n"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL); + ERR("The swap-chain was likely abandoned (e.g. DXGI_ERROR_ACCESS_LOST), so exiting, screen = %d, err = %s\n", m_screen_num, err); break; } } @@ -737,6 +801,8 @@ void SwapChainProcessor::RunCore() int SwapChainProcessor::GetFrameData(std::shared_ptr idd_device, ID3D11Texture2D* desktopimage) { HRESULT status; + char err[256]; + memset(err, 0, 256); if (desktopimage == INVALID_HANDLE_VALUE) { ERR("desktopimage pointer is NULL\n"); @@ -773,6 +839,8 @@ int SwapChainProcessor::GetFrameData(std::shared_ptr idd_device, m_staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; m_staging_desc.MiscFlags = 0; + DBGPRINT("New mode info: %dx%d\n", m_staging_desc.Width, m_staging_desc.Height); + /* Check if all the parameters in the staging descriptor is proper or not */ if (idd_device->Device->CreateTexture2D(&m_staging_desc, NULL, NULL) != S_FALSE) { ERR("Failed Staging Buffer invalid configurations\n"); @@ -780,7 +848,7 @@ int SwapChainProcessor::GetFrameData(std::shared_ptr idd_device, } } - /* Create Texture2D with the staging descriptor parameters */ + /* Create Texture2D with the staging descriptor parameters */ idd_device->Device->CreateTexture2D(&m_staging_desc, NULL, &m_destimage); if (m_destimage == NULL) { ERR("Failed Staging Buffer CreateTexture2D is NULL\n"); @@ -807,18 +875,32 @@ int SwapChainProcessor::GetFrameData(std::shared_ptr idd_device, m_framedata->pitch = m_pitch; m_framedata->stride = m_stride; m_framedata->bitrate = DVSERVER_BBP; + m_framedata->screen_num = m_screen_num; //Assigning the m_staging_buffer buffer addr m_framedata->addr = (void*)m_staging_buffer.pData; + if (!(print_counter++ % PRINT_FREQ)) { + DBGPRINT("m_framedata->width = %d\n", m_framedata->width); + DBGPRINT("m_framedata->height = %d\n", m_framedata->height); + DBGPRINT("m_framedata->format = %d\n", m_framedata->format); + DBGPRINT("m_framedata->pitch = %d\n", m_framedata->pitch); + DBGPRINT("m_framedata->stride = %d\n", m_framedata->stride); + DBGPRINT("m_framedata->bitrate = %d\n", m_framedata->bitrate); + DBGPRINT("m_framedata->screen_num = %d\n", m_framedata->screen_num); + DBGPRINT("m_framedata->addr = %p\n", m_framedata->addr); + } + if (m_resolution_changed == TRUE) { DBGPRINT("ResolutionChanged - sending SET MODE IOCTL\n"); //m_framedata->refresh_rate = FRAME_RR; - if (!DeviceIoControl(devHandle_frame, IOCTL_DVSERVER_SET_MODE, \ + if (!DeviceIoControl(g_DevInfo->get_Handle(), IOCTL_DVSERVER_SET_MODE, \ m_framedata, \ sizeof(struct FrameMetaData), m_ioctlresp_frame, \ sizeof(struct KMDF_IOCTL_Response), \ &m_ioctlresp_size, NULL)) { - ERR("IOCTL_DVSERVER_SET_MODE call failed!\n"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL); + ERR("IOCTL_DVSERVER_SET_MODE call failed with error: %s!\n", err); idd_device->DeviceContext->Unmap(m_destimage, 0); m_destimage->Release(); return DVSERVERUMD_FAILURE; @@ -826,11 +908,13 @@ int SwapChainProcessor::GetFrameData(std::shared_ptr idd_device, m_resolution_changed = FALSE; } - if (!DeviceIoControl(devHandle_frame, IOCTL_DVSERVER_FRAME_DATA, \ + if (!DeviceIoControl(g_DevInfo->get_Handle(), IOCTL_DVSERVER_FRAME_DATA, \ m_framedata, sizeof(struct FrameMetaData), \ m_ioctlresp_frame, sizeof(struct KMDF_IOCTL_Response), \ &m_ioctlresp_size, NULL)) { - ERR("IOCTL_DVSERVER_FRAME_DATA call failed!\n"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL); + ERR("IOCTL_DVSERVER_FRAME_DATA call failed with error: %s!\n", err); idd_device->DeviceContext->Unmap(m_destimage, 0); m_destimage->Release(); return DVSERVERUMD_FAILURE; @@ -926,59 +1010,6 @@ void SwapChainProcessor::GetCursorData() } #endif -/******************************************************************************* -* -* Description -* -* get_dvserver_kmdf_device - This function checks for the DVserverKMD device -* created and opens a handle for DVserverUMD to use -* -* Parameters -* Null -* -* Return val -* int - 0 == SUCCESS, -1 = ERROR -* -******************************************************************************/ -int SwapChainProcessor::get_dvserver_kmdf_device() -{ - DWORD sizeof_deviceinterface_buf = 0; - BOOL ret; - SP_DEVICE_INTERFACE_DATA device_interface_data; - TRACING(); - - device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - devinfo_handle = SetupDiGetClassDevs(NULL, NULL, NULL, DEVINFO_FLAGS); - - ret = SetupDiEnumDeviceInterfaces(devinfo_handle, 0, &GUID_DEVINTERFACE_DVSERVERKMD, 0, &device_interface_data); - if (ret == FALSE) { - ERR("SetupDiEnumDeviceInterfaces failed\n"); - return DVSERVERUMD_FAILURE; - } - - SetupDiGetDeviceInterfaceDetail(devinfo_handle, &device_interface_data, 0, 0, &sizeof_deviceinterface_buf, 0); - if (sizeof_deviceinterface_buf == 0) { - ERR("SetupDiGetDeviceInterfaceDetail failed\n"); - return DVSERVERUMD_FAILURE; - } - - device_iface_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(sizeof_deviceinterface_buf); - if (device_iface_data == NULL) { - ERR("Failed allocating memory for device interface data\n"); - return DVSERVERUMD_FAILURE; - } - - device_iface_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - ret = SetupDiGetDeviceInterfaceDetail(devinfo_handle, &device_interface_data, device_iface_data, sizeof_deviceinterface_buf, 0, 0); - if (ret == FALSE) { - ERR("etupDiGetDeviceInterfaceDetail Failed\nn"); - free(device_iface_data); - return DVSERVERUMD_FAILURE; - } - - return DVSERVERUMD_SUCCESS; -} - #pragma endregion #pragma region IndirectDeviceContext @@ -1010,7 +1041,7 @@ void IndirectDeviceContext::InitAdapter() AdapterCaps.Flags = IDDCX_ADAPTER_FLAGS_USE_SMALLEST_MODE; // Declare basic feature support for the adapter (required) - AdapterCaps.MaxMonitorsSupported = IDD_SAMPLE_MONITOR_COUNT; + AdapterCaps.MaxMonitorsSupported = idd_monitor_count; AdapterCaps.EndPointDiagnostics.Size = sizeof(AdapterCaps.EndPointDiagnostics); AdapterCaps.EndPointDiagnostics.GammaSupport = IDDCX_FEATURE_IMPLEMENTATION_NONE; AdapterCaps.EndPointDiagnostics.TransmissionType = IDDCX_TRANSMISSION_TYPE_WIRED_OTHER; @@ -1073,7 +1104,7 @@ void IndirectDeviceContext::FinishInit(UINT ConnectorIndex) MonitorInfo.MonitorDescription.Size = sizeof(MonitorInfo.MonitorDescription); MonitorInfo.MonitorDescription.Type = IDDCX_MONITOR_DESCRIPTION_TYPE_EDID; - if (ConnectorIndex >= ARRAYSIZE(s_SampleMonitors)) + if (ConnectorIndex >= idd_monitor_count) { MonitorInfo.MonitorDescription.DataSize = 0; MonitorInfo.MonitorDescription.pData = nullptr; @@ -1081,7 +1112,7 @@ void IndirectDeviceContext::FinishInit(UINT ConnectorIndex) else { MonitorInfo.MonitorDescription.DataSize = IndirectSampleMonitor::szEdidBlock; - MonitorInfo.MonitorDescription.pData = const_cast(s_SampleMonitors[ConnectorIndex].pEdidBlock); + MonitorInfo.MonitorDescription.pData = const_cast(g_monitors[ConnectorIndex].pEdidBlock); } // ============================== @@ -1106,7 +1137,7 @@ void IndirectDeviceContext::FinishInit(UINT ConnectorIndex) { // Create a new monitor context object and attach it to the Idd monitor object auto* pMonitorContextWrapper = WdfObjectGet_IndirectMonitorContextWrapper(MonitorCreateOut.MonitorObject); - pMonitorContextWrapper->pContext = new IndirectMonitorContext(MonitorCreateOut.MonitorObject); + pMonitorContextWrapper->pContext = new IndirectMonitorContext(MonitorCreateOut.MonitorObject, ConnectorIndex); // Tell the OS that the monitor has been plugged in IDARG_OUT_MONITORARRIVAL ArrivalOut; @@ -1114,8 +1145,8 @@ void IndirectDeviceContext::FinishInit(UINT ConnectorIndex) } } -IndirectMonitorContext::IndirectMonitorContext(_In_ IDDCX_MONITOR Monitor) : - m_Monitor(Monitor) +IndirectMonitorContext::IndirectMonitorContext(_In_ IDDCX_MONITOR Monitor, _In_ UINT ConnectorIndex) : + m_Monitor(Monitor), m_MonitorIndex(ConnectorIndex) { } @@ -1190,7 +1221,7 @@ void IndirectMonitorContext::AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID Ren else { // Create a new swap-chain processing thread - m_ProcessingThread.reset(new SwapChainProcessor(SwapChain, Device, NewFrameEvent)); + m_ProcessingThread.reset(new SwapChainProcessor(SwapChain, Device, NewFrameEvent, m_MonitorIndex)); } } @@ -1213,7 +1244,7 @@ NTSTATUS IddSampleAdapterInitFinished(IDDCX_ADAPTER AdapterObject, const IDARG_I auto* pDeviceContextWrapper = WdfObjectGet_IndirectDeviceContextWrapper(AdapterObject); if (NT_SUCCESS(pInArgs->AdapterInitStatus)) { - for (DWORD i = 0; i < IDD_SAMPLE_MONITOR_COUNT; i++) + for (DWORD i = 0; i < idd_monitor_count; i++) { pDeviceContextWrapper->pContext->FinishInit(i); } @@ -1268,25 +1299,23 @@ NTSTATUS IddSampleParseMonitorDescription(const IDARG_IN_PARSEMONITORDESCRIPTION if (pInArgs->MonitorDescription.DataSize != IndirectSampleMonitor::szEdidBlock) return STATUS_INVALID_PARAMETER; - DWORD SampleMonitorIdx = 0; - for(; SampleMonitorIdx < ARRAYSIZE(s_SampleMonitors); SampleMonitorIdx++) + for(DWORD SampleMonitorIdx = 0; SampleMonitorIdx < idd_monitor_count; SampleMonitorIdx++) { - if (memcmp(pInArgs->MonitorDescription.pData, s_SampleMonitors[SampleMonitorIdx].pEdidBlock, IndirectSampleMonitor::szEdidBlock) == 0) + if (memcmp(pInArgs->MonitorDescription.pData, g_monitors[SampleMonitorIdx].pEdidBlock, IndirectSampleMonitor::szEdidBlock) == 0) { // Copy the known modes to the output buffer for (DWORD ModeIndex = 0; ModeIndex < IndirectSampleMonitor::szModeList; ModeIndex++) { pInArgs->pMonitorModes[ModeIndex] = CreateIddCxMonitorMode( - s_SampleMonitors[SampleMonitorIdx].pModeList[ModeIndex].Width, - s_SampleMonitors[SampleMonitorIdx].pModeList[ModeIndex].Height, - s_SampleMonitors[SampleMonitorIdx].pModeList[ModeIndex].VSync, + g_monitors[SampleMonitorIdx].pModeList[ModeIndex].Width, + g_monitors[SampleMonitorIdx].pModeList[ModeIndex].Height, + g_monitors[SampleMonitorIdx].pModeList[ModeIndex].VSync, IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR ); } // Set the preferred mode as represented in the EDID - pOutArgs->PreferredMonitorModeIdx = s_SampleMonitors[SampleMonitorIdx].ulPreferredModeIdx; - + pOutArgs->PreferredMonitorModeIdx = g_monitors[SampleMonitorIdx].ulPreferredModeIdx; return STATUS_SUCCESS; } } @@ -1345,12 +1374,14 @@ NTSTATUS IddSampleMonitorQueryModes(IDDCX_MONITOR MonitorObject, const IDARG_IN_ // report the available set of modes for a given output as the intersection of monitor modes with target modes. DWORD SampleMonitorIdx = 0; - for (SampleMonitorIdx=0; SampleMonitorIdx < ARRAYSIZE(s_SampleMonitors); SampleMonitorIdx++) { - if (memcmp(pInArgs->MonitorDescription.pData, s_SampleMonitors[SampleMonitorIdx].pEdidBlock, IndirectSampleMonitor::szEdidBlock) == 0) { + for (SampleMonitorIdx=0; SampleMonitorIdx < idd_monitor_count; SampleMonitorIdx++) { + if (memcmp(pInArgs->MonitorDescription.pData, g_monitors[SampleMonitorIdx].pEdidBlock, IndirectSampleMonitor::szEdidBlock) == 0) { // Copy the known modes to the output buffer for (DWORD ModeIndex = 0; ModeIndex < IndirectSampleMonitor::szModeList; ModeIndex++) { - if (SampleMonitorIdx < ARRAYSIZE(s_SampleMonitors)) { - TargetModes.push_back(CreateIddCxTargetMode(s_SampleMonitors[SampleMonitorIdx].pModeList[ModeIndex].Width, s_SampleMonitors[SampleMonitorIdx].pModeList[ModeIndex].Height, s_SampleMonitors[SampleMonitorIdx].pModeList[ModeIndex].VSync)); + if (SampleMonitorIdx < idd_monitor_count) { + TargetModes.push_back(CreateIddCxTargetMode(g_monitors[SampleMonitorIdx].pModeList[ModeIndex].Width, + g_monitors[SampleMonitorIdx].pModeList[ModeIndex].Height, + g_monitors[SampleMonitorIdx].pModeList[ModeIndex].VSync)); } } pOutArgs->TargetModeBufferOutputCount = (UINT)TargetModes.size(); diff --git a/DVServerUMD/DVServer/Driver.h b/DVServerUMD/DVServer/Driver.h index b7b400d..b14709d 100644 --- a/DVServerUMD/DVServer/Driver.h +++ b/DVServerUMD/DVServer/Driver.h @@ -28,6 +28,7 @@ DEFINE_GUID(GUID_DEVINTERFACE_DVSERVERKMD, #define DVSERVER_BBP 4 // 4 Bytes per pixel #define DEVINFO_FLAGS DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE #define REPORT_FRAME_STATS 60 // we need to report frame stats to OS for every 60 frames +#define PRINT_FREQ 3600 typedef enum FrameType { @@ -86,7 +87,7 @@ namespace Microsoft DWORD Height; DWORD VSync; } pModeList[szModeList]; - const DWORD ulPreferredModeIdx; + DWORD ulPreferredModeIdx; }; /// @@ -105,16 +106,27 @@ namespace Microsoft Microsoft::WRL::ComPtr DeviceContext; }; + class DeviceInfo { + private: + PSP_DEVICE_INTERFACE_DETAIL_DATA device_iface_data; + HDEVINFO devinfo_handle; + HANDLE devHandle_frame; + public: + DeviceInfo(); + ~DeviceInfo(); + int get_dvserver_kmdf_device(); + HANDLE get_Handle() { return devHandle_frame; } + }; + /// /// Manages a thread that consumes buffers from an indirect display swap-chain object. /// class SwapChainProcessor { public: - SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, std::shared_ptr Device, HANDLE NewFrameEvent); + SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, std::shared_ptr Device, HANDLE NewFrameEvent, UINT MonitorIndex); ~SwapChainProcessor(); int GetFrameData(std::shared_ptr idd_device, ID3D11Texture2D* desktopimage); - int get_dvserver_kmdf_device(); void cleanup_resources(); void report_frame_statistics(IDARG_OUT_RELEASEANDACQUIREBUFFER Buffer); void init(); @@ -129,6 +141,7 @@ namespace Microsoft HANDLE m_hAvailableBufferEvent; Microsoft::WRL::Wrappers::Thread m_hThread; Microsoft::WRL::Wrappers::Event m_hTerminateEvent; + int m_screen_num, print_counter; //FrameMetaData related ID3D11Texture2D* m_destimage; @@ -179,7 +192,7 @@ namespace Microsoft class IndirectMonitorContext { public: - IndirectMonitorContext(_In_ IDDCX_MONITOR Monitor); + IndirectMonitorContext(_In_ IDDCX_MONITOR Monitor, _In_ UINT ConnectorIndex); virtual ~IndirectMonitorContext(); void AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent); @@ -191,7 +204,8 @@ namespace Microsoft private: IDDCX_MONITOR m_Monitor; + UINT m_MonitorIndex; std::unique_ptr m_ProcessingThread; - } ; + }; } } diff --git a/DVServerUMD/DVServerUMD_Node/main.cpp b/DVServerUMD/DVServerUMD_Node/main.cpp index 125cd42..577b6c4 100644 --- a/DVServerUMD/DVServerUMD_Node/main.cpp +++ b/DVServerUMD/DVServerUMD_Node/main.cpp @@ -1,7 +1,7 @@ /*=========================================================================== ; Main.cpp ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: MS-PL ; ; File Description: diff --git a/EDIDParser/edidparser.c b/EDIDParser/edidparser.c index 2d5d2a6..c0f7f84 100644 --- a/EDIDParser/edidparser.c +++ b/EDIDParser/edidparser.c @@ -1,7 +1,7 @@ /*=========================================================================== ; edid_parser.c ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: MIT ;--------------------------------------------------------------------------*/ diff --git a/EDIDParser/edidparser.h b/EDIDParser/edidparser.h index 24f9d26..13d8ebc 100644 --- a/EDIDParser/edidparser.h +++ b/EDIDParser/edidparser.h @@ -1,7 +1,7 @@ /*=========================================================================== ; edid_parser.h ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: MIT ;--------------------------------------------------------------------------*/ diff --git a/EDIDParser/edidshared.h b/EDIDParser/edidshared.h index 3de6092..c29a038 100644 --- a/EDIDParser/edidshared.h +++ b/EDIDParser/edidshared.h @@ -1,7 +1,7 @@ /*=========================================================================== ; edidshared.h ;---------------------------------------------------------------------------- -; * Copyright © 2021 Intel Corporation +; Copyright (C) 2021 Intel Corporation ; SPDX-License-Identifier: MIT ;--------------------------------------------------------------------------*/ @@ -10,8 +10,6 @@ #define OUTPUT_MODELIST_SIZE 32 -int parse_edid_data(unsigned char*, struct output_modelist*); - struct edid_qemu_modes { unsigned int width; unsigned int height; @@ -23,4 +21,6 @@ struct output_modelist { unsigned int modelist_size; }; +int parse_edid_data(unsigned char*, struct output_modelist*); + #endif //__EDID_SHARED_H__ diff --git a/Readme.txt b/Readme.txt index 374b4aa..7a06c39 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,14 +1,18 @@ #=========================================================================== #Readme.txt #---------------------------------------------------------------------------- -#* Copyright © 2021 Intel Corporation +#Copyright (C) 2021 Intel Corporation #SPDX-License-Identifier: MIT #--------------------------------------------------------------------------*/ ----------------------------------------------------------- ##### Windows VM QEMU CMD Example ##### ----------------------------------------------------------- -sudo qemu-system-x86_64 -m 4096 -enable-kvm -cpu host -smp cores=4,threads=2,sockets=1 -drive file=.img,format=qcow2,cache=none -usb -usbdevice tablet -device vfio-pci,host=0000:00:02.2 -device e1000,netdev=net0,mac=DE:AD:BE:EF:1C:00 -netdev tap,id=net0 -device virtio-vga,blob=true -display gtk,gl=on,show-fps=on -object memory-backend-memfd,id=mem1,hugetlb=on,size=4096M -machine memory-backend=mem1 +sudo qemu-system-x86_64 -m 4096 -enable-kvm -cpu host -smp cores=4,threads=2,sockets=1 -drive file=.img,format=qcow2,cache=none -device vfio-pci,host=0000:00:02.2 -device e1000,netdev=net0,mac=DE:AD:BE:EF:1C:00 -netdev tap,id=net0 -device virtio-vga,max_outputs=,blob=true -display gtk,gl=on,full-screen=,monitor.1=0,monitor.0=1,show-fps=on -object memory-backend-memfd,id=mem1,hugetlb=on,size=4096M -machine memory-backend=mem1 + +Note: +full-screen=on,monitor.1=0,monitor.0=1 +Secondary display to monitor 0 & Primary display to monitor 1 ----------------------------------------------------------- ##### Common Steps ##### @@ -85,3 +89,4 @@ sudo qemu-system-x86_64 -m 4096 -enable-kvm -cpu host -smp cores=4,threads=2,soc 5) Run your test cases and use cases 6) We need to run DVServerUMD script for every reboot / shutdown --> ".\DVApp.ps1 run" 7) If there are any changes in DVServerUMD driver, copy the updated binaries to DVServer folder --> ".\DVApp.ps1 setup" +