diff --git a/viogpu/common/viogpu.h b/viogpu/common/viogpu.h index 748368e7b..ccbf9e36d 100755 --- a/viogpu/common/viogpu.h +++ b/viogpu/common/viogpu.h @@ -101,6 +101,19 @@ typedef struct virtio_gpu_rect { }GPU_RECT, *PGPU_RECT; #pragma pack() + +#pragma pack(1) +typedef struct virtio_gpu_box { + ULONG x; + ULONG y; + ULONG z; + ULONG width; + ULONG height; + ULONG depth; +}GPU_BOX, * PGPU_BOX; +#pragma pack() + + #define VIRTIO_GPU_FLAG_FENCE (1 << 0) #pragma pack(1) @@ -257,6 +270,110 @@ typedef struct virtio_gpu_resp_edid { }GPU_RESP_EDID, *PGPU_RESP_EDID; #pragma pack() +/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */ + +#define VIRTIO_GPU_MAX_CAPSET_ID 63 +#pragma pack(1) +typedef struct virtio_gpu_cmd_get_capset_info { + GPU_CTRL_HDR hdr; + ULONG capset_index; + ULONG padding; +}GPU_CMD_GET_CAPSET_INFO, * PGPU_CMD_GET_CASPSET_INFO; +#pragma pack() + +/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */ +#pragma pack(1) +typedef struct virtio_gpu_resp_capset_info{ + GPU_CTRL_HDR hdr; + ULONG capset_id; + ULONG capset_max_version; + ULONG capset_max_size; + ULONG padding; +}GPU_RESP_CAPSET_INFO, * PGPU_RESP_CAPSET_INFO; +#pragma pack() + +/* VIRTIO_GPU_CMD_GET_CAPSET */ +#pragma pack(1) +typedef struct virtio_gpu_cmd_get_capset { + GPU_CTRL_HDR hdr; + ULONG capset_id; + ULONG capset_version; +}GPU_CMD_GET_CAPSET, * PGPU_CMD_GET_CASPSET; +#pragma pack() + +/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */ +#pragma pack(1) +typedef struct virtio_gpu_resp_capset { + GPU_CTRL_HDR hdr; + UCHAR capset_data[1]; +}GPU_RESP_CAPSET, * PGPU_RESP_CAPSET; +#pragma pack() + +/* VIRTIO_GPU_CMD_CTX_DESTROY */ +#pragma pack(1) +typedef struct virtio_gpu_ctx_create { + GPU_CTRL_HDR hdr; + ULONG nlen; + ULONG context_init; + UCHAR debug_name[64]; +}GPU_CMD_CTX_CREATE, * PGPU_CMD_CTX_CREATE; +#pragma pack() + +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D*/ +#pragma pack(1) +typedef struct virtio_gpu_resource_create_3d { + GPU_CTRL_HDR hdr; + ULONG res_id; + ULONG target; + ULONG format; + ULONG bind; + ULONG width; + ULONG height; + ULONG depth; + ULONG array_size; + ULONG last_level; + ULONG nr_samples; + ULONG flags; + ULONG padding; +}GPU_CMD_RES_CREATE_3D, * PGPU_CMD_RES_CREATE_3D; +#pragma pack() + +/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */ +typedef struct virtio_gpu_transfer_host_3d { + GPU_CTRL_HDR hdr; + GPU_BOX box; + ULONGLONG offset; + ULONG resource_id; + ULONG level; + ULONG stride; + ULONG layer_stride; +} GPU_CMD_TRANSFER_HOST_3D, *PGPU_CMD_TRANSFER_HOST_3D; + + + +/* VIRTIO_GPU_CMD_CTX_DESTROY */ +#pragma pack(1) +typedef struct virtio_gpu_ctx_destroy { + GPU_CTRL_HDR hdr; +}GPU_CMD_CTX_DESTROY, * PGPU_CMD_CTX_DESTROY; +#pragma pack() + +#pragma pack(1) +typedef struct virtio_gpu_ctx_resource { + GPU_CTRL_HDR hdr; + ULONG resource_id; + ULONG padding; +} GPU_CMD_CTX_RESOURCE, *PGPU_CMD_CTX_RESOURCE; +#pragma pack() + +#pragma pack(1) +typedef struct virtio_gpu_cmd_submit { + GPU_CTRL_HDR hdr; + ULONG size; + ULONG padding; +} GPU_CMD_SUBMIT, * PGPU_CMD_SUBMIT; +#pragma pack() + #define EDID_V1_BLOCK_SIZE 128 diff --git a/viogpu/common/viogpu_queue.cpp b/viogpu/common/viogpu_queue.cpp index 2f56beb92..f76071040 100755 --- a/viogpu/common/viogpu_queue.cpp +++ b/viogpu/common/viogpu_queue.cpp @@ -355,6 +355,124 @@ BOOLEAN CtrlQueue::GetEdidInfo(PGPU_VBUFFER buf, UINT id, PBYTE edid) return TRUE; } +BOOLEAN CtrlQueue::AskCapsetInfo(PGPU_VBUFFER* buf, ULONG idx) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_CMD_GET_CASPSET_INFO cmd; + PGPU_VBUFFER vbuf; + PGPU_RESP_CAPSET_INFO resp_buf; + KEVENT event; + NTSTATUS status; + + resp_buf = reinterpret_cast + (new (NonPagedPoolNx) BYTE[sizeof(GPU_RESP_CAPSET_INFO)]); + + if (!resp_buf) + { + DbgPrint(TRACE_LEVEL_ERROR, ("---> %s Failed allocate %d bytes\n", __FUNCTION__, sizeof(GPU_RESP_CAPSET_INFO))); + return FALSE; + } + cmd = (PGPU_CMD_GET_CASPSET_INFO)AllocCmdResp(&vbuf, sizeof(GPU_CMD_GET_CAPSET_INFO), resp_buf, sizeof(GPU_RESP_CAPSET_INFO)); + RtlZeroMemory(cmd, sizeof(GPU_CMD_GET_CAPSET_INFO)); + + cmd->hdr.type = VIRTIO_GPU_CMD_GET_CAPSET_INFO; + cmd->capset_index = idx; + cmd->padding = 0; + + KeInitializeEvent(&event, NotificationEvent, FALSE); + vbuf->complete_cb = NotifyEventCompleteCB; + vbuf->complete_ctx = &event; + vbuf->no_auto_release = true; + + LARGE_INTEGER timeout = { 0 }; + timeout.QuadPart = Int32x32To64(1000, -10000); + + QueueBuffer(vbuf); + + status = KeWaitForSingleObject(&event, + Executive, + KernelMode, + FALSE, + &timeout + ); + + if (status == STATUS_TIMEOUT) { + DbgPrint(TRACE_LEVEL_FATAL, ("---> Failed to get capset info\n")); + VioGpuDbgBreak(); + return FALSE; + } + + *buf = vbuf; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + + return TRUE; +} + +BOOLEAN CtrlQueue::AskCapset(PGPU_VBUFFER* buf, ULONG capset_id, ULONG capset_size, ULONG capset_version) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_CMD_GET_CASPSET cmd; + PGPU_VBUFFER vbuf; + PGPU_RESP_CAPSET resp_buf; + KEVENT event; + NTSTATUS status; + int resp_size = sizeof(GPU_RESP_CAPSET) + capset_size; + + resp_buf = reinterpret_cast + (new (NonPagedPoolNx) BYTE[resp_size]); + + if (!resp_buf) + { + DbgPrint(TRACE_LEVEL_ERROR, ("---> %s Failed allocate %d bytes\n", __FUNCTION__, sizeof(GPU_RESP_CAPSET_INFO))); + return FALSE; + } + cmd = (PGPU_CMD_GET_CASPSET)AllocCmdResp(&vbuf, sizeof(GPU_CMD_GET_CAPSET), resp_buf, resp_size); + RtlZeroMemory(cmd, sizeof(GPU_CMD_GET_CAPSET)); + + cmd->hdr.type = VIRTIO_GPU_CMD_GET_CAPSET; + cmd->capset_id= capset_id; + cmd->capset_version = capset_version; + + KeInitializeEvent(&event, NotificationEvent, FALSE); + vbuf->complete_cb = NotifyEventCompleteCB; + vbuf->complete_ctx = &event; + vbuf->no_auto_release = true; + + LARGE_INTEGER timeout = { 0 }; + timeout.QuadPart = Int32x32To64(1000, -10000); + + QueueBuffer(vbuf); + + status = KeWaitForSingleObject(&event, + Executive, + KernelMode, + FALSE, + &timeout + ); + + if (status == STATUS_TIMEOUT) { + DbgPrint(TRACE_LEVEL_FATAL, ("---> Failed to get capset\n")); + VioGpuDbgBreak(); + return FALSE; + } + + *buf = vbuf; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + + return TRUE; +} + + void CtrlQueue::CreateResource(UINT res_id, UINT format, UINT width, UINT height) { PAGED_CODE(); @@ -378,6 +496,80 @@ void CtrlQueue::CreateResource(UINT res_id, UINT format, UINT width, UINT height DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); } +void CtrlQueue::CreateResource3D(UINT res_id, VIOGPU_RESOURCE_OPTIONS *options) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_CMD_RES_CREATE_3D cmd; + PGPU_VBUFFER vbuf; + cmd = (PGPU_CMD_RES_CREATE_3D)AllocCmd(&vbuf, sizeof(*cmd)); + RtlZeroMemory(cmd, sizeof(*cmd)); + + cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_3D; + cmd->res_id = res_id; + + cmd->target = options->target; + cmd->format = options->format; + cmd->bind = options->bind; + cmd->width = options->width; + cmd->height = options->height; + cmd->depth = options->depth; + cmd->array_size = options->array_size; + cmd->last_level = options->last_level; + cmd->nr_samples = options->nr_samples; + + //FIXME!!! if + QueueBuffer(vbuf); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + +void CtrlQueue::CreateCtx(UINT ctx_id, UINT context_init) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_CMD_CTX_CREATE cmd; + PGPU_VBUFFER vbuf; + cmd = (PGPU_CMD_CTX_CREATE)AllocCmd(&vbuf, sizeof(*cmd)); + RtlZeroMemory(cmd, sizeof(*cmd)); + + cmd->hdr.type = VIRTIO_GPU_CMD_CTX_CREATE; + cmd->hdr.ctx_id = ctx_id; + cmd->nlen = 0; + cmd->context_init = context_init; + + //FIXME!!! if + QueueBuffer(vbuf); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + +void CtrlQueue::DestroyCtx(UINT ctx_id) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_CMD_CTX_DESTROY cmd; + PGPU_VBUFFER vbuf; + cmd = (PGPU_CMD_CTX_DESTROY)AllocCmd(&vbuf, sizeof(*cmd)); + RtlZeroMemory(cmd, sizeof(*cmd)); + + cmd->hdr.type = VIRTIO_GPU_CMD_CTX_DESTROY; + cmd->hdr.ctx_id = ctx_id; + + //FIXME!!! if + QueueBuffer(vbuf); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + void CtrlQueue::DestroyResource(UINT res_id) { PAGED_CODE(); @@ -485,6 +677,29 @@ void CtrlQueue::TransferToHost2D(UINT res_id, ULONG offset, UINT width, UINT hei DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); } +void CtrlQueue::TransferToHost3D(UINT res_id, GPU_BOX *box) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + PGPU_CMD_TRANSFER_HOST_3D cmd; + PGPU_VBUFFER vbuf; + cmd = (PGPU_CMD_TRANSFER_HOST_3D)AllocCmd(&vbuf, sizeof(*cmd)); + RtlZeroMemory(cmd, sizeof(*cmd)); + + cmd->hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D; + cmd->resource_id = res_id; + cmd->offset = 0; + cmd->level = 0; + cmd->stride = 0; + cmd->layer_stride = 0; + + memcpy(&cmd->box, box, sizeof(GPU_BOX)); + QueueBuffer(vbuf); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + void CtrlQueue::AttachBacking(UINT res_id, PGPU_MEM_ENTRY ents, UINT nents) { PAGED_CODE(); @@ -509,6 +724,98 @@ void CtrlQueue::AttachBacking(UINT res_id, PGPU_MEM_ENTRY ents, UINT nents) DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); } + +void CtrlQueue::CtxResource(bool attach, UINT ctx_id, UINT res_id) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_CMD_CTX_RESOURCE cmd; + PGPU_VBUFFER vbuf; + cmd = (PGPU_CMD_CTX_RESOURCE)AllocCmd(&vbuf, sizeof(*cmd)); + RtlZeroMemory(cmd, sizeof(*cmd)); + + cmd->hdr.type = attach ? VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE : VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE; + cmd->hdr.ctx_id = ctx_id; + cmd->resource_id = res_id; + + QueueBuffer(vbuf); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + +void CtrlQueue::SubmitCommand(void *cmdbuf, ULONG size, ULONG ctx_id, void(*complete_cb)(void*), void *complete_ctx) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_CMD_SUBMIT cmd; + PGPU_VBUFFER vbuf; + cmd = (PGPU_CMD_SUBMIT)AllocCmd(&vbuf, sizeof(*cmd)); + RtlZeroMemory(cmd, sizeof(*cmd)); + + cmd->hdr.type = VIRTIO_GPU_CMD_SUBMIT_3D; + cmd->size = size; + + cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE; + cmd->hdr.fence_id = m_FenceIdr.GetId(); + cmd->hdr.ctx_id = ctx_id; + + vbuf->data_buf = cmdbuf; + vbuf->data_size = size; + + vbuf->complete_cb = complete_cb; + vbuf->complete_ctx = complete_ctx; + + QueueBuffer(vbuf); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +void CtrlQueue::TransferHostCmd(bool to_host, ULONG ctx_id, VIOGPU_TRANSFER_CMD* options, void(*complete_cb)(void*), void *complete_ctx) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_CMD_TRANSFER_HOST_3D cmd; + PGPU_VBUFFER vbuf; + cmd = (PGPU_CMD_TRANSFER_HOST_3D)AllocCmd(&vbuf, sizeof(*cmd)); + RtlZeroMemory(cmd, sizeof(*cmd)); + + cmd->hdr.type = to_host ? VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D : VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D; + + cmd->resource_id = options->res_id; + + cmd->box.x = options->box.x; + cmd->box.y = options->box.y; + cmd->box.z = options->box.z; + cmd->box.width = options->box.width; + cmd->box.height = options->box.height; + cmd->box.depth = options->box.depth; + + cmd->offset = options->offset; + cmd->level = options->level; + cmd->stride = options->stride; + cmd->layer_stride = options->layer_stride; + + cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE; + cmd->hdr.fence_id = m_FenceIdr.GetId(); + + cmd->hdr.ctx_id = ctx_id; + + vbuf->complete_cb = complete_cb; + vbuf->complete_ctx = complete_ctx; + + QueueBuffer(vbuf); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + PAGED_CODE_SEG_END #define SGLIST_SIZE 256 diff --git a/viogpu/common/viogpu_queue.h b/viogpu/common/viogpu_queue.h index 1480dcf8b..7e53a83bf 100755 --- a/viogpu/common/viogpu_queue.h +++ b/viogpu/common/viogpu_queue.h @@ -191,10 +191,18 @@ class CtrlQueue : public VioGpuQueue PGPU_VBUFFER DequeueBuffer(_Out_ UINT* len); void CreateResource(UINT res_id, UINT format, UINT width, UINT height); + void CreateResource3D(UINT res_id, VIOGPU_RESOURCE_OPTIONS* options); void DestroyResource(UINT id); + void CtxResource(bool attach, UINT ctx_id, UINT res_id); + + void SubmitCommand(void* cmdbuf, ULONG size, ULONG ctx_id, void(*complete_cb)(void*), void* complete_ctx); + void TransferHostCmd(bool to_host, ULONG res_id, VIOGPU_TRANSFER_CMD* options, void(*complete_cb)(void*), void* complete_ctx); + void SetScanout(UINT scan_id, UINT res_id, UINT width, UINT height, UINT x, UINT y); void ResFlush(UINT res_id, UINT width, UINT height, UINT x, UINT y); void TransferToHost2D(UINT res_id, ULONG offset, UINT width, UINT height, UINT x, UINT y); + void TransferToHost3D(UINT res_id, GPU_BOX* box); + void AttachBacking(UINT res_id, PGPU_MEM_ENTRY ents, UINT nents); void DetachBacking(UINT id); @@ -202,6 +210,11 @@ class CtrlQueue : public VioGpuQueue BOOLEAN AskDisplayInfo(PGPU_VBUFFER* buf); BOOLEAN AskEdidInfo(PGPU_VBUFFER* buf, UINT id); BOOLEAN GetEdidInfo(PGPU_VBUFFER buf, UINT id, PBYTE edid); + BOOLEAN AskCapsetInfo(PGPU_VBUFFER* buf, ULONG idx); + BOOLEAN AskCapset(PGPU_VBUFFER* buf, ULONG capset_id, ULONG capset_size, ULONG capset_version); + + void CreateCtx(UINT ctx_id, UINT context_init); + void DestroyCtx(UINT ctx_id); private: VioGpuIdr m_FenceIdr; diff --git a/viogpu/shared/viogpum.h b/viogpu/shared/viogpum.h index 8641cef01..457e87c47 100755 --- a/viogpu/shared/viogpum.h +++ b/viogpu/shared/viogpum.h @@ -29,11 +29,42 @@ #pragma once -extern "C" { +#include + + +#pragma pack(1) +typedef struct _VIOGPU_BOX { + ULONG x; + ULONG y; + ULONG z; + ULONG width; + ULONG height; + ULONG depth; +} VIOGPU_BOX; +#pragma pack() + +// ================= QueryAdapterInfo UMDRIVERPRIVATE +#define VIOGPU_IAM 0x56696f475055 // Identified for queryadapterinfo (VioGPU as hex) + +typedef struct _VIOGPU_ADAPTERINFO { + ULONGLONG IamVioGPU; // Should be set by driver to VIOGPU_IAM + struct { + UINT Supports3d : 1; + UINT Reserved : 31; + } Flags; + ULONGLONG SupportedCapsetIDs; +} VIOGPU_ADAPTERINFO; + +// ================= ESCAPES +#define VIOGPU_GET_DEVICE_ID 0x000 +#define VIOGPU_GET_CUSTOM_RESOLUTION 0x001 +#define VIOGPU_GET_CAPS 0x002 + +#define VIOGPU_RES_INFO 0x100 +#define VIOGPU_RES_BUSY 0x101 + +#define VIOGPU_CTX_INIT 0x200 -} -#define VIOGPU_GET_DEVICE_ID 0x00 -#define VIOGPU_GET_CUSTOM_RESOLUTION 0x01 #pragma pack(1) typedef struct _VIOGPU_DISP_MODE { @@ -42,6 +73,49 @@ typedef struct _VIOGPU_DISP_MODE { }VIOGPU_DISP_MODE, *PVIOGPU_DISP_MODE; #pragma pack() + +#pragma pack(1) +typedef struct _VIOGPU_PARAM_REQ { + ULONG ParamId; + UINT64 Value; +}VIOGPU_PARAM_REQ; +#pragma pack() + + +#pragma pack(1) +typedef struct _VIOGPU_CAPSET_REQ { + ULONG CapsetId; + ULONG Version; + ULONG Size; + UCHAR *Capset; +}VIOGPU_CAPSET_REQ; +#pragma pack() + + +#pragma pack(1) +typedef struct _VIOGPU_RES_INFO_REQ { + D3DKMT_HANDLE ResHandle; + ULONG Id; +}VIOGPU_RES_INFO_REQ; +#pragma pack() + + +#pragma pack(1) +typedef struct _VIOGPU_RES_BUSY_REQ { + D3DKMT_HANDLE ResHandle; + BOOL Wait; + BOOL IsBusy; +}VIOGPU_RES_BUSY_REQ; +#pragma pack() + + +#pragma pack(1) +typedef struct _VIOGPU_CTX_INIT_REQ { + UINT CapsetID; +}VIOGPU_CTX_INIT_REQ; +#pragma pack() + + #pragma pack(1) typedef struct _VIOGPU_ESCAPE{ USHORT Type; @@ -49,10 +123,76 @@ typedef struct _VIOGPU_ESCAPE{ union { ULONG Id; VIOGPU_DISP_MODE Resolution; + VIOGPU_PARAM_REQ Parameter; + VIOGPU_CAPSET_REQ Capset; + + VIOGPU_RES_INFO_REQ ResourceInfo; + VIOGPU_RES_BUSY_REQ ResourceBusy; + + VIOGPU_CTX_INIT_REQ CtxInit; } DUMMYUNIONNAME; } VIOGPU_ESCAPE, *PVIOGPU_ESCAPE; #pragma pack() +// ================= CreateResource +#pragma pack(1) +typedef struct _VIOGPU_RESOURCE_OPTIONS { + ULONG target; + ULONG format; + ULONG bind; + ULONG width; + ULONG height; + ULONG depth; + ULONG array_size; + ULONG last_level; + ULONG nr_samples; + ULONG flags; +} VIOGPU_RESOURCE_OPTIONS; + + +#pragma pack(1) +typedef struct _VIOGPU_CREATE_RESOURCE_EXCHANGE { + ULONG magic; +} VIOGPU_CREATE_RESOURCE_EXCHANGE; +#pragma pack() + +#pragma pack(1) +typedef struct _VIOGPU_CREATE_ALLOCATION_EXCHANGE { + VIOGPU_RESOURCE_OPTIONS ResourceOptions; + ULONGLONG Size; +} VIOGPU_CREATE_ALLOCATION_EXCHANGE; +#pragma pack() + + +// ================= COMMAND BUFFER +#define VIOGPU_CMD_NOP 0x0 +#define VIOGPU_CMD_SUBMIT 0x1 // Submit Command to virgl +#define VIOGPU_CMD_TRANSFER_TO_HOST 0x2 // Transfer resource to host +#define VIOGPU_CMD_TRANSFER_FROM_HOST 0x3 // Transfer resource to host + +#pragma pack(1) +typedef struct _VIOGPU_COMMAND_HDR { + UINT type; + UINT size; +} VIOGPU_COMMAND_HDR; +#pragma pack() + + +#pragma pack(1) +typedef struct _VIOGPU_TRANSFER_CMD { + ULONG res_id; + + VIOGPU_BOX box; + + ULONGLONG offset; + ULONG level; + ULONG stride; + ULONG layer_stride; +} VIOGPU_TRANSFER_CMD; +#pragma pack() + + + #define BASE_NAMED_OBJECTS L"\\BaseNamedObjects\\" #define GLOBAL_OBJECTS L"Global\\" #define RESOLUTION_EVENT_NAME L"VioGpuResolutionEvent" diff --git a/viogpu/viogpu.sln b/viogpu/viogpu.sln index b4381fe38..e5cb4a6ae 100755 --- a/viogpu/viogpu.sln +++ b/viogpu/viogpu.sln @@ -18,6 +18,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "viogpusc", "viogpusc\viogpu EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "viogpuap", "viogpuap\viogpuap.vcxproj", "{8C2B5F43-18E2-41B6-AEBC-8B6704F7FCC6}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "viogpu3d", "viogpu3d\viogpu3d.vcxproj", "{ACF8BC77-62AA-4CF3-B19B-CA96CB240168}" + ProjectSection(ProjectDependencies) = postProject + {D572573A-7D73-404D-8DFA-7727278C242E} = {D572573A-7D73-404D-8DFA-7727278C242E} + {8C2B5F43-18E2-41B6-AEBC-8B6704F7FCC6} = {8C2B5F43-18E2-41B6-AEBC-8B6704F7FCC6} + {01D87C47-437A-4A16-8FD9-33FA5C99339E} = {01D87C47-437A-4A16-8FD9-33FA5C99339E} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Win10 Release|ARM64 = Win10 Release|ARM64 @@ -101,6 +108,19 @@ Global {8C2B5F43-18E2-41B6-AEBC-8B6704F7FCC6}.Win8.1 Release|x64.Build.0 = Win8.1 Release|x64 {8C2B5F43-18E2-41B6-AEBC-8B6704F7FCC6}.Win8.1 Release|x86.ActiveCfg = Win8.1 Release|Win32 {8C2B5F43-18E2-41B6-AEBC-8B6704F7FCC6}.Win8.1 Release|x86.Build.0 = Win8.1 Release|Win32 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win10 Release|ARM64.ActiveCfg = Win10 Release|ARM64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win10 Release|x64.ActiveCfg = Win10 Release|x64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win10 Release|x64.Build.0 = Win10 Release|x64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win10 Release|x64.Deploy.0 = Win10 Release|x64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win10 Release|x86.ActiveCfg = Win10 Release|Win32 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win8 Release|ARM64.ActiveCfg = Win10 Release|ARM64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win8 Release|x64.ActiveCfg = Win10 Release|x64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win8 Release|x86.ActiveCfg = Win10 Release|Win32 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win8.1 Release|ARM64.ActiveCfg = Win10 Release|ARM64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win8.1 Release|x64.ActiveCfg = Win10 Release|x64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win8.1 Release|x64.Build.0 = Win10 Release|x64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win8.1 Release|x64.Deploy.0 = Win10 Release|x64 + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168}.Win8.1 Release|x86.ActiveCfg = Win10 Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/viogpu/viogpu3d/BUILDING.md b/viogpu/viogpu3d/BUILDING.md new file mode 100644 index 000000000..97e150021 --- /dev/null +++ b/viogpu/viogpu3d/BUILDING.md @@ -0,0 +1,25 @@ +# Building viogpu3d driver + +This repository contains kernel-mode part of viogpu3d driver, and full-driver will be build only if there is user-mode driver dll's available in directory pointed by environment variable `MESA_PATH`. + +## Build mesa +Now inside virtual machine with build tools installed create working directory, then inside it (this assumes use of Powershell): +1. Create mesa prefix dir `mkdir mesa_prefix` and set env `MESA_PREFIX` to its path: `$env:MESA_PREFIX="$PWD\mesa_prefix"` +2. Acquire [mesa source code](https://gitlab.freedesktop.org/mesa/mesa) and then cd into it `cd mesa` +3. Create build directory `mkdir build && cd build` +4. Configure build `meson .. --prefix=$env:MESA_PREFIX -Dgallium-drivers=virgl -Dgallium-d3d10umd=true -Dgallium-wgl-dll-name=viogpu_wgl -Dgallium-d3d10-dll-name=viogpu_d3d10`. Build options explained: + * `--prefix=$env:MESA_PREFIX` set installation path to dir created in step 1 + * `-Dgallium-drivers=virgl` build only virgl driver + * `-Dgallium-d3d10umd=true` build DirectX 10 user-mode driver (opengl one is build by default) + * `-Dgallium-d3d10-dll-name=viogpu_d3d10` name of generated d3d10 dll to `viogpu_d3d10.dll` + * `-Dgallium-wgl-dll-name=viogpu_wgl` name of generated wgl dll to `viogpu_wgl.dll` +5. Build and install (to mesa prefix): `ninja install` + +## Build driver +Now that mesa is build and installed into `%MESA_PREFIX%` viogpu3d will be built (in case `%MESA_PREFIX` is not set viogpu3d inf generation is skipped) +1. Acquire [drivers source code](https://github.com/virtio-win/kvm-guest-drivers-windows) and cd into it `cd kvm-guest-drivers-windows` +2. Go to viogpu `cd viogpu` +3. (optional, but very useful) setup test code signning from visual studio +4. Call build `.\build_AllNoSdv.bat` + +Built driver will be available at `kvm-guest-drivers-windows\viogpu\viogpu3d\objfre_win10_amd64\amd64\viogpu3d`. diff --git a/viogpu/viogpu3d/clean.bat b/viogpu/viogpu3d/clean.bat new file mode 100644 index 000000000..10b762c79 --- /dev/null +++ b/viogpu/viogpu3d/clean.bat @@ -0,0 +1,16 @@ +@echo on + +rmdir /S /Q .\Install + +for /d %%x in (objfre_*) do rmdir /S /Q %%x +for /d %%x in (objchk_*) do rmdir /S /Q %%x +rmdir /S /Q .\sdv +rmdir /S /Q .\sdv.temp +rmdir /S /Q .\codeql_db + +del /F *.log *.wrn *.err *.sdf *.sdv *.xml +del viogpudo.dvl.xml +del viogpudo.dvl-compat.xml +del build.sdv.config +del sdv-map.h + diff --git a/viogpu/viogpu3d/driver.cpp b/viogpu/viogpu3d/driver.cpp new file mode 100644 index 000000000..f005b86fd --- /dev/null +++ b/viogpu/viogpu3d/driver.cpp @@ -0,0 +1,1233 @@ +/* + * Copyright (C) 2019-2020 Red Hat, Inc. + * + * Written By: Vadim Rozenfeld + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met : + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and / or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of their contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "driver.h" +#include "helper.h" +#include "baseobj.h" +#include "viogpu_adapter.h" +#include "viogpu_device.h" +#if !DBG +#include "driver.tmh" +#endif + +#pragma code_seg(push) +#pragma code_seg("INIT") + +int nDebugLevel; +int virtioDebugLevel; +int bDebugPrint; +int bBreakAlways; + +tDebugPrintFunc VirtioDebugPrintProc; + +#ifdef DBG +void InitializeDebugPrints(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) +{ + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(RegistryPath); + bDebugPrint = 0; + virtioDebugLevel = 0; + nDebugLevel = TRACE_LEVEL_NONE; + bBreakAlways = 0; + + bDebugPrint = 1; + virtioDebugLevel = 0x5; + bBreakAlways = 1; + nDebugLevel = TRACE_LEVEL_WARNING; +#if defined(COM_DEBUG) + VirtioDebugPrintProc = DebugPrintFuncSerial; +#elif defined(PRINT_DEBUG) + VirtioDebugPrintProc = DebugPrintFuncKdPrint; +#endif +} +#endif + +#include +#include "viogpu_device.h" + +#pragma code_seg(push) +#pragma code_seg("PAGE") +extern "C" +NTSTATUS +DriverEntry( + _In_ DRIVER_OBJECT* pDriverObject, + _In_ UNICODE_STRING* pRegistryPath) +{ + PAGED_CODE(); + WPP_INIT_TRACING(pDriverObject, pRegistryPath) + DbgPrint(TRACE_LEVEL_FATAL, ("---> VIOGPU FULL build on on %s %s\n", __DATE__, __TIME__)); + DRIVER_INITIALIZATION_DATA InitialData = { 0 }; + + + InitialData.Version = DXGKDDI_INTERFACE_VERSION_WDDM1_3; + + InitialData.DxgkDdiAddDevice = VioGpu3DAddDevice; + InitialData.DxgkDdiStartDevice = VioGpu3DStartDevice; + InitialData.DxgkDdiStopDevice = VioGpu3DStopDevice; + InitialData.DxgkDdiRemoveDevice = VioGpu3DRemoveDevice; + + InitialData.DxgkDdiDispatchIoRequest = VioGpu3DDispatchIoRequest; + InitialData.DxgkDdiInterruptRoutine = VioGpu3DInterruptRoutine; + InitialData.DxgkDdiDpcRoutine = VioGpu3DDpcRoutine; + + InitialData.DxgkDdiQueryChildRelations = VioGpu3DQueryChildRelations; + InitialData.DxgkDdiQueryChildStatus = VioGpu3DQueryChildStatus; + InitialData.DxgkDdiQueryDeviceDescriptor = VioGpu3DQueryDeviceDescriptor; + InitialData.DxgkDdiSetPowerState = VioGpu3DSetPowerState; + InitialData.DxgkDdiResetDevice = VioGpu3DResetDevice; + InitialData.DxgkDdiUnload = VioGpu3DUnload; + + InitialData.DxgkDdiQueryAdapterInfo = VioGpu3DQueryAdapterInfo; + InitialData.DxgkDdiEscape = VioGpu3DEscape; + InitialData.DxgkDdiCreateAllocation = VioGpu3DCreateAllocation; + InitialData.DxgkDdiOpenAllocation = VioGpu3DOpenAllocation; + InitialData.DxgkDdiCloseAllocation = VioGpu3DCloseAllocation; + InitialData.DxgkDdiDescribeAllocation = VioGpu3DDescribeAllocation; + InitialData.DxgkDdiDestroyAllocation = VioGpu3DDestroyAllocation; + InitialData.DxgkDdiGetStandardAllocationDriverData = VioGpu3DGetStandardAllocationDriverData; + InitialData.DxgkDdiBuildPagingBuffer = VioGpu3DBuildPagingBuffer; + + InitialData.DxgkDdiCreateContext = VioGpu3DDdiCreateContext; + InitialData.DxgkDdiDestroyContext = VioGpu3DDdiDestroyContext; + + InitialData.DxgkDdiPresent = VioGpu3DPresent; + InitialData.DxgkDdiRender = VioGpu3DRender; + InitialData.DxgkDdiPatch = VioGpu3DPatch; + InitialData.DxgkDdiSubmitCommand = VioGpu3DSubmitCommand; + + InitialData.DxgkDdiSetPointerPosition = VioGpu3DSetPointerPosition; + InitialData.DxgkDdiSetPointerShape = VioGpu3DSetPointerShape; + InitialData.DxgkDdiIsSupportedVidPn = VioGpu3DIsSupportedVidPn; + InitialData.DxgkDdiRecommendFunctionalVidPn = VioGpu3DRecommendFunctionalVidPn; + InitialData.DxgkDdiEnumVidPnCofuncModality = VioGpu3DEnumVidPnCofuncModality; + InitialData.DxgkDdiSetVidPnSourceVisibility = VioGpu3DSetVidPnSourceVisibility; + InitialData.DxgkDdiCommitVidPn = VioGpu3DCommitVidPn; + InitialData.DxgkDdiUpdateActiveVidPnPresentPath = VioGpu3DUpdateActiveVidPnPresentPath; + InitialData.DxgkDdiSetVidPnSourceAddress = VioGpu3DSetVidPnSourceAddress; + InitialData.DxgkDdiRecommendMonitorModes = VioGpu3DRecommendMonitorModes; + InitialData.DxgkDdiQueryVidPnHWCapability = VioGpu3DQueryVidPnHWCapability; + InitialData.DxgkDdiSystemDisplayEnable = VioGpu3DSystemDisplayEnable; + InitialData.DxgkDdiSystemDisplayWrite = VioGpu3DSystemDisplayWrite; + + InitialData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = VioGpu3DStopDeviceAndReleasePostDisplayOwnership; + + InitialData.DxgkDdiCreateDevice = VioGpu3DCreateDevice; + InitialData.DxgkDdiDestroyDevice = VioGpu3DDestroyDevice; + + InitialData.DxgkDdiPreemptCommand = VioGpu3DDdiPreemptCommand; + InitialData.DxgkDdiResetFromTimeout = VioGpu3DDdiResetFromTimeout; + InitialData.DxgkDdiRestartFromTimeout = VioGpu3DDdiRestartFromTimeout; + InitialData.DxgkDdiCollectDbgInfo = VioGpu3DDdiCollectDbgInfo; + InitialData.DxgkDdiQueryCurrentFence = VioGpu3DDdiQueryCurrentFence; + + InitialData.DxgkDdiQueryEngineStatus = VioGpu3DDdiQueryEngineStatus; + InitialData.DxgkDdiResetEngine = VioGpu3DDdiResetEngine; + InitialData.DxgkDdiCancelCommand = VioGpu3DDdiCancelCommand; + + InitialData.DxgkDdiGetNodeMetadata = VioGpu3DDdiGetNodeMetadata; + InitialData.DxgkDdiControlInterrupt = VioGpu3DDdiControlInterrupt; + InitialData.DxgkDdiGetScanLine = VioGpu3DDdiGetScanLine; + + NTSTATUS Status = DxgkInitialize(pDriverObject, pRegistryPath, &InitialData); + + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("DxgkInitialize failed with Status: 0x%X\n", Status)); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} +// END: Init Code +#pragma code_seg(pop) + +#pragma code_seg(push) +#pragma code_seg("PAGE") + +// +// PnP DDIs +// + +VOID +VioGpu3DUnload(VOID) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--> %s\n", __FUNCTION__)); + WPP_CLEANUP(NULL); +} + +NTSTATUS +VioGpu3DAddDevice( + _In_ DEVICE_OBJECT* pPhysicalDeviceObject, + _Outptr_ PVOID* ppDeviceContext) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + if ((pPhysicalDeviceObject == NULL) || + (ppDeviceContext == NULL)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("One of pPhysicalDeviceObject (%p), ppDeviceContext (%p) is NULL", + pPhysicalDeviceObject, ppDeviceContext)); + return STATUS_INVALID_PARAMETER; + } + *ppDeviceContext = NULL; + + VioGpuAdapter* pAdapter = new(NonPagedPoolNx) VioGpuAdapter(pPhysicalDeviceObject); + if (pAdapter == NULL) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pAdapter failed to be allocated")); + return STATUS_NO_MEMORY; + } + + *ppDeviceContext = pAdapter; + + DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s ppDeviceContext = %p\n", __FUNCTION__, pAdapter)); + return STATUS_SUCCESS; +} + +NTSTATUS +VioGpu3DRemoveDevice( + _In_ VOID* pDeviceContext) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_FATAL, ("---> %s 0x%p\n", __FUNCTION__, pDeviceContext)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + + if (pAdapter) + { + delete pAdapter; + } + + DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS +VioGpu3DStartDevice( + _In_ VOID* pDeviceContext, + _In_ DXGK_START_INFO* pDxgkStartInfo, + _In_ DXGKRNL_INTERFACE* pDxgkInterface, + _Out_ ULONG* pNumberOfViews, + _Out_ ULONG* pNumberOfChildren) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + return pAdapter->StartDevice(pDxgkStartInfo, pDxgkInterface, pNumberOfViews, pNumberOfChildren); +} + +NTSTATUS +VioGpu3DStopDevice( + _In_ VOID* pDeviceContext) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + return pAdapter->StopDevice(); +} + + +NTSTATUS +VioGpu3DDispatchIoRequest( + _In_ VOID* pDeviceContext, + _In_ ULONG VidPnSourceId, + _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + if (!pAdapter->IsDriverActive()) + { + VIOGPU_LOG_ASSERTION1("VioGpuAdapter (0x%I64x) is being called when not active!", pAdapter); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->DispatchIoRequest(VidPnSourceId, pVideoRequestPacket); +} + +NTSTATUS +VioGpu3DSetPowerState( + _In_ VOID* pDeviceContext, + _In_ ULONG HardwareUid, + _In_ DEVICE_POWER_STATE DevicePowerState, + _In_ POWER_ACTION ActionType) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + if (!pAdapter->IsDriverActive()) + { + return STATUS_SUCCESS; + } + return pAdapter->SetPowerState(HardwareUid, DevicePowerState, ActionType); +} + +NTSTATUS +VioGpu3DQueryChildRelations( + _In_ VOID* pDeviceContext, + _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, + _In_ ULONG ChildRelationsSize) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + return pAdapter->QueryChildRelations(pChildRelations, ChildRelationsSize); +} + +NTSTATUS +VioGpu3DQueryChildStatus( + _In_ VOID* pDeviceContext, + _Inout_ DXGK_CHILD_STATUS* pChildStatus, + _In_ BOOLEAN NonDestructiveOnly) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + return pAdapter->QueryChildStatus(pChildStatus, NonDestructiveOnly); +} + +NTSTATUS +VioGpu3DQueryDeviceDescriptor( + _In_ VOID* pDeviceContext, + _In_ ULONG ChildUid, + _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + if (!pAdapter->IsDriverActive()) + { + DbgPrint(TRACE_LEVEL_WARNING, ("VIOGPU (%p) is being called when not active!", pAdapter)); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->QueryDeviceDescriptor(ChildUid, pDeviceDescriptor); +} + + +NTSTATUS +APIENTRY +VioGpu3DQueryAdapterInfo( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + return pAdapter->QueryAdapterInfo(pQueryAdapterInfo); +} + + +NTSTATUS +APIENTRY +VioGpu3DDdiGetNodeMetadata( + _In_ CONST HANDLE hAdapter, + UINT NodeOrdinal, + _Out_ DXGKARG_GETNODEMETADATA* pGetNodeMetadata) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + UNREFERENCED_PARAMETER(hAdapter); + UNREFERENCED_PARAMETER(NodeOrdinal); + + pGetNodeMetadata->EngineType = DXGK_ENGINE_TYPE_3D; + pGetNodeMetadata->Flags.Value = 0; + + return STATUS_SUCCESS; +}; + + +NTSTATUS +APIENTRY +VioGpu3DSetPointerPosition( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + UNREFERENCED_PARAMETER(pSetPointerPosition); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + DbgPrint(TRACE_LEVEL_ERROR, ("VioGpu (%p) is being called when not active!", pAdapter)); + VioGpuDbgBreak(); + return STATUS_UNSUCCESSFUL; + } + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +APIENTRY +VioGpu3DSetPointerShape( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + UNREFERENCED_PARAMETER(pSetPointerShape); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s VioGpu (%p) is being called when not active!\n", __FUNCTION__, pAdapter)); + return STATUS_UNSUCCESSFUL; + } + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +APIENTRY +VioGpu3DEscape( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_ESCAPE* pEscape + ) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s VioGpu (%p) is being called when not active!\n", __FUNCTION__, pAdapter)); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->Escape(pEscape); +} + +NTSTATUS +APIENTRY +VioGpu3DCreateAllocation( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_CREATEALLOCATION* pCreateAllocation +) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s VioGpu (%p) is being called when not active!\n", __FUNCTION__, pAdapter)); + return STATUS_UNSUCCESSFUL; + } + return VioGpuAllocation::DxgkCreateAllocation(pAdapter, pCreateAllocation); +} + + +NTSTATUS +APIENTRY +VioGpu3DDescribeAllocation( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_DESCRIBEALLOCATION* pDescribeAllocation +) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAllocation* pAllocation = reinterpret_cast(pDescribeAllocation->hAllocation); + VIOGPU_ASSERT_CHK(pAllocation != NULL); + + return pAllocation->DescribeAllocation(pDescribeAllocation); +} + +NTSTATUS +APIENTRY +VioGpu3DOpenAllocation( + _In_ CONST HANDLE hDevice, + _In_ CONST DXGKARG_OPENALLOCATION* pOpenAllocation +) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hDevice != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuDevice* pDxContext = reinterpret_cast(hDevice); + return pDxContext->OpenAllocation(pOpenAllocation); +} + +NTSTATUS +APIENTRY +VioGpu3DCloseAllocation( + _In_ CONST HANDLE hDevice, + _In_ CONST DXGKARG_CLOSEALLOCATION* pCloseAllocation +) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hDevice != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + for (ULONG i = 0; i < pCloseAllocation->NumAllocations; i++) { + VioGpuDeviceAllocation* allocation = reinterpret_cast(pCloseAllocation->pOpenHandleList[i]); + if (allocation != NULL) { + delete allocation; + } + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +APIENTRY +VioGpu3DDestroyAllocation( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_DESTROYALLOCATION* pDestroyAllocation) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(hAdapter); + VIOGPU_ASSERT_CHK(pDestroyAllocation != NULL); + + for (ULONG i = 0; i < pDestroyAllocation->NumAllocations; i++) { + VioGpuAllocation* allocation = reinterpret_cast(pDestroyAllocation->pAllocationList[i]); + if (allocation != NULL) { + delete allocation; + } + } + + if (pDestroyAllocation->Flags.DestroyResource) { + VioGpuResource* resource = reinterpret_cast(pDestroyAllocation->hResource); + if (resource != NULL) { + delete resource; + } + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s \n", __FUNCTION__)); + return STATUS_SUCCESS; +} + + + +NTSTATUS +APIENTRY +VioGpu3DGetStandardAllocationDriverData( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_GETSTANDARDALLOCATIONDRIVERDATA* pStandardAllocation +) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(hAdapter); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + return VioGpuAllocation::GetStandardAllocationDriverData(pStandardAllocation); +} + + +NTSTATUS +APIENTRY +VioGpu3DBuildPagingBuffer( + _In_ CONST HANDLE hAdapter, + _In_ DXGKARG_BUILDPAGINGBUFFER* pBuildPagingBuffer +) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + VIOGPU_ASSERT(pBuildPagingBuffer != NULL); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s operation=%d\n", __FUNCTION__, pBuildPagingBuffer->Operation)); + + switch (pBuildPagingBuffer->Operation) + { + case DXGK_OPERATION_MAP_APERTURE_SEGMENT: + { + if (pBuildPagingBuffer->MapApertureSegment.hAllocation == NULL) { + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s (map aperture segment) no allocation specified\n", __FUNCTION__)); + return STATUS_SUCCESS; + } + + VioGpuAllocation* allocation = reinterpret_cast(pBuildPagingBuffer->MapApertureSegment.hAllocation); + NTSTATUS Status = allocation->MapApertureSegment(pBuildPagingBuffer); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s (map aperture segment)\n", __FUNCTION__)); + return Status; + } + case DXGK_OPERATION_UNMAP_APERTURE_SEGMENT: + { + if (pBuildPagingBuffer->UnmapApertureSegment.hAllocation == NULL) { + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s (map aperture segment) no allocation specified\n", __FUNCTION__)); + return STATUS_SUCCESS; + } + + VioGpuAllocation* allocation = reinterpret_cast(pBuildPagingBuffer->UnmapApertureSegment.hAllocation); + NTSTATUS Status = allocation->UnmapApertureSegment(pBuildPagingBuffer); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s (unmap aperture segment)\n", __FUNCTION__)); + return Status; + } + default: { + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s (unknown operation %d)\n", __FUNCTION__, pBuildPagingBuffer->Operation)); + return STATUS_NOT_SUPPORTED; + } + }; +} + + + +NTSTATUS +APIENTRY +VioGpu3DPatch( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_PATCH* pPatch) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + return STATUS_UNSUCCESSFUL; + } + return pAdapter->commander.Patch(pPatch); +}; + +NTSTATUS +APIENTRY +VioGpu3DSubmitCommand( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SUBMITCOMMAND* pSubmitCommand) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + //DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + //DbgPrint(TRACE_LEVEL_ERROR, ("Fake imp %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + //DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s VioGpu (%p) is being called when not active!\n", __FUNCTION__, pAdapter)); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->commander.SubmitCommand(pSubmitCommand); +}; + + + +NTSTATUS +APIENTRY +VioGpu3DCreateDevice( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_CREATEDEVICE* pCreateDevice +) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s VioGpu (%p) is being called when not active!\n", __FUNCTION__, pAdapter)); + return STATUS_UNSUCCESSFUL; + } + + + pCreateDevice->hDevice = new (NonPagedPoolNx)VioGpuDevice(pAdapter); + if (!pCreateDevice->hDevice) + { + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s failed to allocate VioGpuDevice\n", __FUNCTION__)); + return STATUS_NO_MEMORY; + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +APIENTRY +VioGpu3DDestroyDevice( + _In_ VOID* pDeviceContext) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_FATAL, ("---> %s 0x%p\n", __FUNCTION__, pDeviceContext)); + + VioGpuDevice* pDxContext = reinterpret_cast(pDeviceContext); + + if (pDxContext) + { + delete pDxContext; + } + + DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + + +NTSTATUS +APIENTRY +VioGpu3DDdiCreateContext( + _In_ CONST HANDLE hDevice, + _Inout_ DXGKARG_CREATECONTEXT *pCreateContext) { + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + // We currently don't have sepraration between context and device + pCreateContext->hContext = hDevice; + + pCreateContext->ContextInfo.DmaBufferSegmentSet = 0; + pCreateContext->ContextInfo.DmaBufferSize = 256 * 1024; + pCreateContext->ContextInfo.DmaBufferPrivateDataSize = 40; + + pCreateContext->ContextInfo.AllocationListSize = DXGK_ALLOCATION_LIST_SIZE_GDICONTEXT; + pCreateContext->ContextInfo.PatchLocationListSize = DXGK_ALLOCATION_LIST_SIZE_GDICONTEXT; + + return STATUS_SUCCESS; +}; + +NTSTATUS +APIENTRY +VioGpu3DDdiDestroyContext( + _In_ CONST HANDLE hContext) { + PAGED_CODE(); + + UNREFERENCED_PARAMETER(hContext); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + return STATUS_SUCCESS; +}; + + + +NTSTATUS +APIENTRY +VioGpu3DPresent( + _In_ CONST HANDLE hDevice, + _Inout_ DXGKARG_PRESENT* pPresent) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hDevice != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuDevice* pDxContext = reinterpret_cast(hDevice); + return pDxContext->Present(pPresent); +} + +NTSTATUS +APIENTRY +VioGpu3DRender( + _In_ CONST HANDLE hDevice, + _Inout_ DXGKARG_RENDER* pRender) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hDevice != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuDevice* pDxContext = reinterpret_cast(hDevice); + return pDxContext->Render(pRender); +} + +NTSTATUS +APIENTRY +VioGpu3DStopDeviceAndReleasePostDisplayOwnership( + _In_ VOID* pDeviceContext, + _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo) +{ + PAGED_CODE(); + NTSTATUS status = STATUS_SUCCESS; + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + if (pAdapter) + { + status = pAdapter->StopDeviceAndReleasePostDisplayOwnership(TargetId, DisplayInfo); + } + return status; +} + +NTSTATUS +APIENTRY +VioGpu3DIsSupportedVidPn( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + DbgPrint(TRACE_LEVEL_WARNING, ("VIOGPU (%p) is being called when not active!", pAdapter)); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->vidpn.IsSupportedVidPn(pIsSupportedVidPn); +} + +NTSTATUS +APIENTRY +VioGpu3DRecommendFunctionalVidPn( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + VIOGPU_LOG_ASSERTION1("VIOGPU (%p) is being called when not active!", pAdapter); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->vidpn.RecommendFunctionalVidPn(pRecommendFunctionalVidPn); +} + +NTSTATUS +APIENTRY +VioGpu3DRecommendVidPnTopology( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + VIOGPU_LOG_ASSERTION1("VIOGPU (%p) is being called when not active!", pAdapter); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->vidpn.RecommendVidPnTopology(pRecommendVidPnTopology); +} + +NTSTATUS +APIENTRY +VioGpu3DRecommendMonitorModes( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + VIOGPU_LOG_ASSERTION1("VIOGPU (%p) is being called when not active!", pAdapter); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->vidpn.RecommendMonitorModes(pRecommendMonitorModes); +} + +NTSTATUS +APIENTRY +VioGpu3DEnumVidPnCofuncModality( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + VIOGPU_LOG_ASSERTION1("VIOGPU (%p) is being called when not active!", pAdapter); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->vidpn.EnumVidPnCofuncModality(pEnumCofuncModality); +} + +NTSTATUS +APIENTRY +VioGpu3DSetVidPnSourceVisibility( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + VIOGPU_LOG_ASSERTION1("VIOGPU (%p) is being called when not active!", pAdapter); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->vidpn.SetVidPnSourceVisibility(pSetVidPnSourceVisibility); +} + +NTSTATUS +APIENTRY +VioGpu3DCommitVidPn( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + VIOGPU_LOG_ASSERTION1("VIOGPU (%p) is being called when not active!", pAdapter); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->vidpn.CommitVidPn(pCommitVidPn); +} + +NTSTATUS +APIENTRY +VioGpu3DUpdateActiveVidPnPresentPath( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + VIOGPU_LOG_ASSERTION1("VIOGPU (%p) is being called when not active!", pAdapter); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->vidpn.UpdateActiveVidPnPresentPath(pUpdateActiveVidPnPresentPath); +} + +NTSTATUS +APIENTRY +VioGpu3DQueryVidPnHWCapability( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps) +{ + PAGED_CODE(); + VIOGPU_ASSERT_CHK(hAdapter != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + if (!pAdapter->IsDriverActive()) + { + VIOGPU_LOG_ASSERTION1("VIOGPU (%p) is being called when not active!", pAdapter); + return STATUS_UNSUCCESSFUL; + } + return pAdapter->vidpn.QueryVidPnHWCapability(pVidPnHWCaps); +} + +NTSTATUS +APIENTRY +VioGpu3DDdiControlInterrupt( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGK_INTERRUPT_TYPE InterruptType, + _In_ BOOLEAN EnableInterrupt) { + PAGED_CODE(); + + UNREFERENCED_PARAMETER(hAdapter); + UNREFERENCED_PARAMETER(InterruptType); + UNREFERENCED_PARAMETER(EnableInterrupt); + + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s not implemented\n", __FUNCTION__)); + return STATUS_SUCCESS; +}; + + + +NTSTATUS +APIENTRY +VioGpu3DDdiGetScanLine( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_GETSCANLINE* pGetScanLine +) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(hAdapter); + UNREFERENCED_PARAMETER(pGetScanLine); + + DbgBreakPoint(); DbgPrint(TRACE_LEVEL_ERROR, ("Not imp %s\n", __FUNCTION__)); return STATUS_NO_MEMORY; +} + + +//END: Paged Code +#pragma code_seg(pop) + +#pragma code_seg(push) +#pragma code_seg() +// BEGIN: Non-Paged Code + +VOID +VioGpu3DDpcRoutine( + _In_ VOID* pDeviceContext) +{ + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + if (!pAdapter->IsHardwareInit()) + { + DbgPrint(TRACE_LEVEL_FATAL, ("VioGpu (%p) is being called when not active!", pAdapter)); + return; + } + pAdapter->DpcRoutine(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +BOOLEAN +VioGpu3DInterruptRoutine( + _In_ VOID* pDeviceContext, + _In_ ULONG MessageNumber) +{ + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + return pAdapter->InterruptRoutine(MessageNumber); +} + + +NTSTATUS VioGpu3DSetVidPnSourceAddress( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETVIDPNSOURCEADDRESS* pSetVidPnSourceAddress +) +{ + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(hAdapter); + pAdapter->vidpn.SetVidPnSourceAddress(pSetVidPnSourceAddress); + + return STATUS_SUCCESS; +} + +VOID +VioGpu3DResetDevice( + _In_ VOID* pDeviceContext) +{ + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + pAdapter->ResetDevice(); +} + +NTSTATUS +APIENTRY +VioGpu3DSystemDisplayEnable( + _In_ VOID* pDeviceContext, + _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, + _Out_ UINT* Width, + _Out_ UINT* Height, + _Out_ D3DDDIFORMAT* ColorFormat) +{ + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + return pAdapter->vidpn.SystemDisplayEnable(TargetId, Flags, Width, Height, ColorFormat); +} + +VOID +APIENTRY +VioGpu3DSystemDisplayWrite( + _In_ VOID* pDeviceContext, + _In_ VOID* Source, + _In_ UINT SourceWidth, + _In_ UINT SourceHeight, + _In_ UINT SourceStride, + _In_ UINT PositionX, + _In_ UINT PositionY) +{ + VIOGPU_ASSERT_CHK(pDeviceContext != NULL); + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__)); + + VioGpuAdapter* pAdapter = reinterpret_cast(pDeviceContext); + pAdapter->vidpn.SystemDisplayWrite(Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY); +} + + + + +NTSTATUS +APIENTRY +VioGpu3DDdiPreemptCommand( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_PREEMPTCOMMAND* pPreemptCommand) { + UNREFERENCED_PARAMETER(hAdapter); + UNREFERENCED_PARAMETER(pPreemptCommand); + + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s UNSUPPORTED PREEMPTION FUNCTION fence_id=%d\n", __FUNCTION__, pPreemptCommand->PreemptionFenceId)); + + return STATUS_SUCCESS; +}; + +NTSTATUS +APIENTRY +VioGpu3DDdiRestartFromTimeout( + _In_ CONST HANDLE hAdapter) { + UNREFERENCED_PARAMETER(hAdapter); + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s UNSUPPORTED PREEMPTION FUNCTION\n", __FUNCTION__)); + + return STATUS_SUCCESS; +}; + + +NTSTATUS +APIENTRY +VioGpu3DDdiCancelCommand( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_CANCELCOMMAND* pCancelCommand) { + UNREFERENCED_PARAMETER(hAdapter); + UNREFERENCED_PARAMETER(pCancelCommand); + + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s UNSUPPORTED PREEMPTION FUNCTION\n", __FUNCTION__)); + + return STATUS_SUCCESS; +}; + +NTSTATUS +APIENTRY +VioGpu3DDdiQueryCurrentFence( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_QUERYCURRENTFENCE* pCurrentFence) { + UNREFERENCED_PARAMETER(hAdapter); + UNREFERENCED_PARAMETER(pCurrentFence); + + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s UNSUPPORTED PREEMPTION FUNCTION\n", __FUNCTION__)); + + return STATUS_SUCCESS; +}; + +NTSTATUS +APIENTRY +VioGpu3DDdiResetEngine( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_RESETENGINE* pResetEngine) { + UNREFERENCED_PARAMETER(hAdapter); + UNREFERENCED_PARAMETER(pResetEngine); + + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s UNSUPPORTED PREEMPTION FUNCTION\n", __FUNCTION__)); + + return STATUS_SUCCESS; +}; + +NTSTATUS +APIENTRY +VioGpu3DDdiQueryEngineStatus( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_QUERYENGINESTATUS* pQueryEngineStatus) { + UNREFERENCED_PARAMETER(hAdapter); + UNREFERENCED_PARAMETER(pQueryEngineStatus); + + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s UNSUPPORTED PREEMPTION FUNCTION\n", __FUNCTION__)); + + return STATUS_SUCCESS; +}; + +NTSTATUS +APIENTRY +VioGpu3DDdiCollectDbgInfo( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_COLLECTDBGINFO* pCollectDbgInfo) { + UNREFERENCED_PARAMETER(hAdapter); + UNREFERENCED_PARAMETER(pCollectDbgInfo); + + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s UNSUPPORTED PREEMPTION FUNCTION\n", __FUNCTION__)); + + return STATUS_SUCCESS; +}; + +NTSTATUS +APIENTRY +VioGpu3DDdiResetFromTimeout( + _In_ CONST HANDLE hAdapter) { + UNREFERENCED_PARAMETER(hAdapter); + + DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s UNSUPPORTED PREEMPTION FUNCTION\n", __FUNCTION__)); + + return STATUS_SUCCESS; +}; + +#if defined(DBG) + +#if defined(COM_DEBUG) + +#define RHEL_DEBUG_PORT ((PUCHAR)0x3F8) +#define TEMP_BUFFER_SIZE 256 + +void DebugPrintFuncSerial(CONST char *format, ...) +{ + char buf[TEMP_BUFFER_SIZE]; + NTSTATUS status; + size_t len; + va_list list; + va_start(list, format); + status = RtlStringCbVPrintfA(buf, sizeof(buf), format, list); + if (status == STATUS_SUCCESS) + { + len = strlen(buf); + } + else + { + len = 2; + buf[0] = 'O'; + buf[1] = '\n'; + } + if (len) + { + WRITE_PORT_BUFFER_UCHAR(RHEL_DEBUG_PORT, (PUCHAR)buf, (ULONG)len); + WRITE_PORT_UCHAR(RHEL_DEBUG_PORT, '\r'); + } + va_end(list); +} +#endif + +#if defined(PRINT_DEBUG) +void DebugPrintFuncKdPrint(CONST char *format, ...) +{ + va_list list; + va_start(list, format); + vDbgPrintEx(DPFLTR_DEFAULT_ID, 9 | DPFLTR_MASK, format, list); + va_end(list); +} +#endif + +#endif +#pragma code_seg(pop) // End Non-Paged Code + diff --git a/viogpu/viogpu3d/driver.h b/viogpu/viogpu3d/driver.h new file mode 100644 index 000000000..20f7ee0b1 --- /dev/null +++ b/viogpu/viogpu3d/driver.h @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2019-2020 Red Hat, Inc. + * + * Written By: Vadim Rozenfeld + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met : + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and / or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of their contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once +#include "helper.h" + +extern "C" +DRIVER_INITIALIZE DriverEntry; + +VOID +VioGpu3DUnload(VOID); + +NTSTATUS +VioGpu3DAddDevice( + _In_ DEVICE_OBJECT* pPhysicalDeviceObject, + _Outptr_ PVOID* ppDeviceContext); + +NTSTATUS +VioGpu3DRemoveDevice( + _In_ VOID* pDeviceContext); + +NTSTATUS +VioGpu3DStartDevice( + _In_ VOID* pDeviceContext, + _In_ DXGK_START_INFO* pDxgkStartInfo, + _In_ DXGKRNL_INTERFACE* pDxgkInterface, + _Out_ ULONG* pNumberOfViews, + _Out_ ULONG* pNumberOfChildren); + +NTSTATUS +VioGpu3DStopDevice( + _In_ VOID* pDeviceContext); + +VOID +VioGpu3DResetDevice( + _In_ VOID* pDeviceContext); + + +NTSTATUS +VioGpu3DDispatchIoRequest( + _In_ VOID* pDeviceContext, + _In_ ULONG VidPnSourceId, + _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket); + +NTSTATUS +VioGpu3DSetPowerState( + _In_ VOID* pDeviceContext, + _In_ ULONG HardwareUid, + _In_ DEVICE_POWER_STATE DevicePowerState, + _In_ POWER_ACTION ActionType); + +NTSTATUS +VioGpu3DQueryChildRelations( + _In_ VOID* pDeviceContext, + _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, + _In_ ULONG ChildRelationsSize); + +NTSTATUS +VioGpu3DQueryChildStatus( + _In_ VOID* pDeviceContext, + _Inout_ DXGK_CHILD_STATUS* pChildStatus, + _In_ BOOLEAN NonDestructiveOnly); + +NTSTATUS +VioGpu3DQueryDeviceDescriptor( + _In_ VOID* pDeviceContext, + _In_ ULONG ChildUid, + _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor); + +BOOLEAN +VioGpu3DInterruptRoutine( + _In_ VOID* pDeviceContext, + _In_ ULONG MessageNumber); + +VOID +VioGpu3DDpcRoutine( + _In_ VOID* pDeviceContext); + +NTSTATUS +APIENTRY +VioGpu3DQueryAdapterInfo( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo); + +NTSTATUS +APIENTRY +VioGpu3DDdiGetNodeMetadata( + _In_ CONST HANDLE hAdapter, + UINT NodeOrdinal, + _Out_ DXGKARG_GETNODEMETADATA* pGetNodeMetadata); + +NTSTATUS +APIENTRY +VioGpu3DSetPointerPosition( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition); + +NTSTATUS +APIENTRY +VioGpu3DSetPointerShape( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape); + +NTSTATUS +APIENTRY +VioGpu3DEscape( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_ESCAPE* pEscape); + + +NTSTATUS +APIENTRY +VioGpu3DCreateAllocation( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_CREATEALLOCATION* pCreateAllocation); + +NTSTATUS +APIENTRY +VioGpu3DOpenAllocation( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_OPENALLOCATION* pOpenAllocation); + +NTSTATUS +APIENTRY +VioGpu3DCloseAllocation( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_CLOSEALLOCATION* pCloseAllocation); + +NTSTATUS +APIENTRY +VioGpu3DDescribeAllocation( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_DESCRIBEALLOCATION* pDescribeAllocation +); + +NTSTATUS +APIENTRY +VioGpu3DDestroyAllocation( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_DESTROYALLOCATION* pDestroyAllocation); + + +NTSTATUS +APIENTRY +VioGpu3DGetStandardAllocationDriverData( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_GETSTANDARDALLOCATIONDRIVERDATA* pStandardAllocation +); + + +NTSTATUS +APIENTRY +VioGpu3DBuildPagingBuffer( + _In_ CONST HANDLE hAdapter, + _In_ DXGKARG_BUILDPAGINGBUFFER* pCreateAllocation +); + +NTSTATUS +APIENTRY +VioGpu3DPatch( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_PATCH* pPatch); + +NTSTATUS +APIENTRY +VioGpu3DSubmitCommand( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SUBMITCOMMAND* pSubmitCommand); + +NTSTATUS +APIENTRY +VioGpu3DCreateDevice( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_CREATEDEVICE* pCreateDevice +); + + +NTSTATUS +APIENTRY +VioGpu3DDestroyDevice( + _In_ VOID* pDeviceContext); + + +NTSTATUS +APIENTRY +VioGpu3DDdiCreateContext( + _In_ CONST HANDLE hDevice, + _Inout_ DXGKARG_CREATECONTEXT* pCreateContext); + +NTSTATUS +APIENTRY +VioGpu3DDdiDestroyContext( + _In_ CONST HANDLE hContext); + +NTSTATUS +APIENTRY +VioGpu3DPresent( + _In_ CONST HANDLE hDevice, + _Inout_ DXGKARG_PRESENT* pPresent); + +NTSTATUS +APIENTRY +VioGpu3DRender( + _In_ CONST HANDLE hDevice, + _Inout_ DXGKARG_RENDER* pRender); + +NTSTATUS +APIENTRY +VioGpu3DIsSupportedVidPn( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn); + +NTSTATUS +APIENTRY +VioGpu3DRecommendFunctionalVidPn( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn); + +NTSTATUS +APIENTRY +VioGpu3DRecommendVidPnTopology( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology); + +NTSTATUS +APIENTRY +VioGpu3DRecommendMonitorModes( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); + +NTSTATUS +APIENTRY +VioGpu3DEnumVidPnCofuncModality( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality); + +NTSTATUS +APIENTRY +VioGpu3DSetVidPnSourceVisibility( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility); + +NTSTATUS VioGpu3DSetVidPnSourceAddress( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_SETVIDPNSOURCEADDRESS* pSetVidPnSourceAddress +); + +NTSTATUS +APIENTRY +VioGpu3DCommitVidPn( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn); + +NTSTATUS +APIENTRY +VioGpu3DUpdateActiveVidPnPresentPath( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath); + +NTSTATUS +APIENTRY +VioGpu3DQueryVidPnHWCapability( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps); + +NTSTATUS +APIENTRY +VioGpu3DDdiControlInterrupt( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGK_INTERRUPT_TYPE InterruptType, + _In_ BOOLEAN EnableInterrupt); + +NTSTATUS +APIENTRY +VioGpu3DDdiGetScanLine( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_GETSCANLINE* pGetScanLine +); + +NTSTATUS +APIENTRY +VioGpu3DStopDeviceAndReleasePostDisplayOwnership( + _In_ VOID* pDeviceContext, + _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo); + +NTSTATUS +APIENTRY +VioGpu3DSystemDisplayEnable( + _In_ VOID* pDeviceContext, + _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, + _Out_ UINT* Width, + _Out_ UINT* Height, + _Out_ D3DDDIFORMAT* ColorFormat); + +VOID +APIENTRY +VioGpu3DSystemDisplayWrite( + _In_ VOID* pDeviceContext, + _In_ VOID* Source, + _In_ UINT SourceWidth, + _In_ UINT SourceHeight, + _In_ UINT SourceStride, + _In_ UINT PositionX, + _In_ UINT PositionY); + +NTSTATUS +APIENTRY +VioGpu3DDdiPreemptCommand( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_PREEMPTCOMMAND* pPreemptCommand); + +NTSTATUS +APIENTRY +VioGpu3DDdiRestartFromTimeout( + _In_ CONST HANDLE hAdapter); + + +NTSTATUS +APIENTRY +VioGpu3DDdiCancelCommand( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_CANCELCOMMAND* pCancelCommand); + +NTSTATUS +APIENTRY +VioGpu3DDdiQueryCurrentFence( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_QUERYCURRENTFENCE* pCurrentFence); + +NTSTATUS +APIENTRY +VioGpu3DDdiResetEngine( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_RESETENGINE* pResetEngine); + +NTSTATUS +APIENTRY +VioGpu3DDdiQueryEngineStatus( + _In_ CONST HANDLE hAdapter, + _Inout_ DXGKARG_QUERYENGINESTATUS* pQueryEngineStatus); + +NTSTATUS +APIENTRY +VioGpu3DDdiCollectDbgInfo( + _In_ CONST HANDLE hAdapter, + _In_ CONST DXGKARG_COLLECTDBGINFO* pCollectDbgInfo); + +NTSTATUS +APIENTRY +VioGpu3DDdiResetFromTimeout(_In_ CONST HANDLE hAdapter); diff --git a/viogpu/viogpu3d/resource.h b/viogpu/viogpu3d/resource.h new file mode 100644 index 000000000..cc524fe9a --- /dev/null +++ b/viogpu/viogpu3d/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by viogpudo.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/viogpu/viogpu3d/trace.h b/viogpu/viogpu3d/trace.h new file mode 100644 index 000000000..56dc63c1d --- /dev/null +++ b/viogpu/viogpu3d/trace.h @@ -0,0 +1,67 @@ +#pragma once + +#define DBG 1 + +#ifndef TRACE_LEVEL_INFORMATION +#define TRACE_LEVEL_NONE 0 // Tracing is not on +#define TRACE_LEVEL_FATAL 1 // Abnormal exit or termination +#define TRACE_LEVEL_ERROR 2 // Severe errors that need logging +#define TRACE_LEVEL_WARNING 3 // Warnings such as allocation failure +#define TRACE_LEVEL_INFORMATION 4 // Includes non-error cases(e.g.,Entry-Exit) +#define TRACE_LEVEL_VERBOSE 5 // Detailed traces from intermediate steps +#define TRACE_LEVEL_RESERVED6 6 +#define TRACE_LEVEL_RESERVED7 7 +#define TRACE_LEVEL_RESERVED8 8 +#define TRACE_LEVEL_RESERVED9 9 +#endif // TRACE_LEVEL_INFORMATION + +#if DBG +#define PRINT_DEBUG 1 +//#define COM_DEBUG 1 + + extern int nDebugLevel; + extern int bBreakAlways; + + void DebugPrintFuncSerial(const char *format, ...); + void DebugPrintFuncKdPrint(const char *format, ...); +#define DbgExpandArguments(...) __VA_ARGS__ +#define DbgPrint(Level, MSG) \ + if (Level <= nDebugLevel) VirtioDebugPrintProc(DbgExpandArguments MSG); +#define VioGpuDbgBreak()\ + if (KD_DEBUGGER_ENABLED && !KD_DEBUGGER_NOT_PRESENT && bBreakAlways) DbgBreakPoint(); + +#define WPP_INIT_TRACING(driver, regpath) InitializeDebugPrints(driver, regpath); +#define WPP_CLEANUP(driver) +#else +//#define DbgPrint(level, line) {}; + +#define WPP_CHECK_FOR_NULL_STRING // to prevent exceptions due to NULL strings. + +// Tracing GUID - {88FF4AF9-B7B4-40FF-94AD-271B4777ED97} + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + VioGpu3DTraceGuid, (88FF4AF9,B7B4,40FF,94AD,271B4777ED97), \ + WPP_DEFINE_BIT(TRACE_ALL) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ + (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +#define VioGpuDbgBreak() {} + +// begin_wpp config +// USEPREFIX (DbgPrint, "%!STDPREFIX! %!FUNC!"); +// DbgPrint{FLAG = TRACE_ALL}(LEVEL, (MSG, ...)); +// end_wpp +// + +#endif diff --git a/viogpu/viogpu3d/viogpu3d.inx b/viogpu/viogpu3d/viogpu3d.inx new file mode 100644 index 000000000..8b5d60d96 --- /dev/null +++ b/viogpu/viogpu3d/viogpu3d.inx @@ -0,0 +1,116 @@ +;/*++ +; +;INX_COPYRIGHT_1 +;INX_COPYRIGHT_2 +; +; viogpu3d.inf +; + +[Version] +Signature="$Windows NT$" +Class=Display +ClassGUID={4d36e968-e325-11ce-bfc1-08002be10318} +Provider=%RHEL% +DriverVer= 09/05/2018, 1.01.01.0002 +CatalogFile=viogpu3d.cat +PnpLockdown = 1 + +[DestinationDirs] +VioGpu3D_Files.Driver = 12 ; drivers +VioGpu3D_Files.Usermode = 13 ; DriverStore + + + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +viogpu3d.sys = 1,,f +viogpu_d3d10.dll = 1,, +viogpu_wgl.dll = 1,, +z.dll = 1,, + +[Manufacturer] +%RHEL%=RHEL,NT$ARCH$ + +[RHEL.NT$ARCH$] +%VioGpu3D.DeviceDesc% = VioGpu3D_Inst, PCI\VEN_1AF4&DEV_1050&SUBSYS_11001AF4&REV_01 + +[VioGpu3D_Files.Driver] +viogpu3d.sys,,,2 + +[VioGpu3D_Files.Usermode] +viogpu_d3d10.dll,,,0 +viogpu_wgl.dll,,,0 +z.dll,,,0 + +[VioGpu3D_Inst] +Include=msdv.inf +FeatureScore=F9 +CopyFiles=VioGpu3D_Files.Driver, VioGpu3D_Files.Usermode +AddReg=VioGpu3D_DeviceSettings + + +[VioGpu3D_Inst.Services] +AddService = VioGpu3D,0x00000002,VioGpu3D_Service_Inst, VioGpu3D_EventLog_Inst + +[VioGpu3D_Inst.HW] +AddReg = VioGpu3D_PCI_MSIX + + +[VioGpu3D_Service_Inst] +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_IGNORE% +ServiceBinary = %12%\viogpu3d.sys + +[VioGpu3D_EventLog_Inst] +AddReg = VioGpu3D_EventLog_Inst.AddReg + +[VioGpu3D_EventLog_Inst.AddReg] +HKR,,EventMessageFile,%REG_EXPAND_SZ%,"%%SystemRoot%%\System32\IoLogMsg.dll" +HKR,,TypesSupported,%REG_DWORD%,7 + +[VioGpu3D_DeviceSettings] +HKR,, HWCursor, %REG_DWORD%, 0 +HKR,, FlexResolution, %REG_DWORD%, 1 +HKR,, UsePhysicalMemory, %REG_DWORD%, 0 +HKR,, UserModeDriverName, %REG_MULTI_SZ%, %13%\viogpu_d3d10.dll,%13%\viogpu_d3d10.dll,%13%\viogpu_d3d10.dll,%13%\viogpu_d3d10.dll +HKR,, OpenGLDriverName, %REG_MULTI_SZ%, %13%\viogpu_wgl.dll +HKR,, OpenGLFlags, %REG_DWORD%, 3 +HKR,, OpenGLVersion, %REG_DWORD%, 4096 +HKLM,"SYSTEM\CurrentControlSet\Control\GraphicsDrivers\Scheduler",EnablePreemption,%REG_DWORD%,0 +HKLM,"SYSTEM\CurrentControlSet\Control\GraphicsDrivers",TdrDebugMode,%REG_DWORD%,1 + +[VioGpu3D_PCI_MSIX] +HKR, "Interrupt Management",, 0x00000010 +HKR, "Interrupt Management\MessageSignaledInterruptProperties",, 0x00000010 +HKR, "Interrupt Management\MessageSignaledInterruptProperties", MSISupported, 0x00010001, 0 +HKR, "Interrupt Management\MessageSignaledInterruptProperties", MessageNumberLimit, 0x00010001, 4 +;HKR, "Interrupt Management\Affinity Policy",, 0x00000010 +;HKR, "Interrupt Management\Affinity Policy", DevicePolicy, 0x00010001, 5 +;HKR, "Interrupt Management\Affinity Policy", DevicePriority, 0x00010001, 3 + +[Strings] + +; *******Localizable Strings******* +diskId1 = "Red Hat VirtIO GPU controller Installation Disk" +VioGpu3D.DeviceDesc = "Red Hat VirtIO GPU 3D controller" +RHEL = "Red Hat, Inc." + +; *******Non Localizable Strings******* +SERVICE_BOOT_START = 0x0 +SERVICE_SYSTEM_START = 0x1 +SERVICE_AUTO_START = 0x2 +SERVICE_DEMAND_START = 0x3 +SERVICE_DISABLED = 0x4 + +SERVICE_KERNEL_DRIVER = 0x1 +SERVICE_ERROR_IGNORE = 0x0 +SERVICE_ERROR_NORMAL = 0x1 +SERVICE_ERROR_SEVERE = 0x2 +SERVICE_ERROR_CRITICAL = 0x3 + +REG_MULTI_SZ = 0x00010000 +REG_EXPAND_SZ = 0x00020000 +REG_DWORD = 0x00010001 diff --git a/viogpu/viogpu3d/viogpu3d.props b/viogpu/viogpu3d/viogpu3d.props new file mode 100644 index 000000000..13f12a084 --- /dev/null +++ b/viogpu/viogpu3d/viogpu3d.props @@ -0,0 +1,24 @@ + + + + + false + false + true + ..\ + true + true + true + viogpu3d.inx + VioGpu3DCopyrightStrings + + + + + + diff --git a/viogpu/viogpu3d/viogpu3d.rc b/viogpu/viogpu3d/viogpu3d.rc new file mode 100644 index 000000000..06c896366 Binary files /dev/null and b/viogpu/viogpu3d/viogpu3d.rc differ diff --git a/viogpu/viogpu3d/viogpu3d.vcxproj b/viogpu/viogpu3d/viogpu3d.vcxproj new file mode 100644 index 000000000..7b433354c --- /dev/null +++ b/viogpu/viogpu3d/viogpu3d.vcxproj @@ -0,0 +1,218 @@ + + + + + Win10 Release + ARM64 + + + Win10 Release + Win32 + + + Win10 Release + x64 + + + + {ACF8BC77-62AA-4CF3-B19B-CA96CB240168} + {E8938A1F-DD6F-435F-9067-9502172282FD} + v4.5.2 + 12.0 + Win10 Release + Win32 + Off + $(LatestTargetPlatformVersion) + viogpu3d + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + WDM + 1 + Universal + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + WDM + 1 + Universal + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + WDM + 1 + Universal + + + + + + + + + + + + DbgengKernelDebugger + objfre_win10_x86\i386\ + objfre_win10_x86\i386\ + viogpu3d + + + viogpu3d + DbgengKernelDebugger + objfre_win10_arm64\arm64\ + objfre_win10_arm64\arm64\ + + + DbgengKernelDebugger + objfre_win10_amd64\amd64\ + objfre_win10_amd64\amd64\ + viogpu3d + + + dvl + + + + copy /Y $(ProjectDir)viogpu3d.DVL.XML $(ProjectDir)$(PackOne_DestinationPrefix)Install\$(TargetOS)\$(TargetArch) + $(ProjectDir)viogpu3d.DVL.XML + $(ProjectDir)$(PackOne_DestinationPrefix)Install\$(TargetOS)\$(TargetArch)\viogpu3d.DVL.XML + + + + + %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(DDK_LIB_PATH)\displib.lib + ..\..\VirtIO\objfre_win8_x86\amd64\ + + + + + %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(DDK_LIB_PATH)\displib.lib;virtiolib.lib + ..\..\VirtIO\$(OutDir);%(AdditionalLibraryDirectories) + + + $(IntDir);%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);..\common;..\shared;..\..\VirtIO;..\viogpu3d\; + VIOGPU_3D=1;%(PreprocessorDefinitions) + true + ..\viogpu3d\trace.h + + false + + + + + + + + + %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(DDK_LIB_PATH)\displib.lib;virtiolib.lib + ..\..\VirtIO\$(OutDir);%(AdditionalLibraryDirectories) + + + $(IntDir);%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);..\common;..\shared;..\..\VirtIO;..\viogpu3d\; + VIOGPU_3D=1;%(PreprocessorDefinitions) + true + trace.h + + + + + + %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(DDK_LIB_PATH)\displib.lib + ..\..\VirtIO\objfre_win10_x86\amd64\ + + + + + $(IntDir);%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);..\common;..\shared;..\..\VirtIO;..\viogpu3d\; + VIOGPU_3D=1;%(PreprocessorDefinitions) + true + trace.h + + + %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(DDK_LIB_PATH)\displib.lib;virtiolib.lib + ..\..\VirtIO\$(OutDir);%(AdditionalLibraryDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/viogpu/viogpu3d/viogpu3d.vcxproj.filters b/viogpu/viogpu3d/viogpu3d.vcxproj.filters new file mode 100644 index 000000000..3a4d3b79c --- /dev/null +++ b/viogpu/viogpu3d/viogpu3d.vcxproj.filters @@ -0,0 +1,104 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Driver Files + + + \ No newline at end of file diff --git a/viogpu/viogpu3d/viogpu_adapter.cpp b/viogpu/viogpu3d/viogpu_adapter.cpp new file mode 100644 index 000000000..7d2cefb15 --- /dev/null +++ b/viogpu/viogpu3d/viogpu_adapter.cpp @@ -0,0 +1,1562 @@ +/* + * Copyright (C) 2019-2020 Red Hat, Inc. + * + * Written By: Vadim Rozenfeld + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met : + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and / or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of their contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "helper.h" +#include "driver.h" +#include "viogpu_adapter.h" +#include "baseobj.h" +#include "bitops.h" +#include "viogpum.h" +#include "viogpu_device.h" +#if !DBG +#include "viogpudo.tmh" +#endif + +static UINT g_InstanceId = 0; + +struct NOTIFY_CONTEXT { + DXGKRNL_INTERFACE* pDxgkInterface; + DXGKARGCB_NOTIFY_INTERRUPT_DATA* interrupt; + BOOL triggerDpc; +}; + +BOOLEAN NotifyRoutine(PVOID ctx_void) { + //DbgPrint(TRACE_LEVEL_ERROR, ("<---> %s\n", __FUNCTION__)); + NOTIFY_CONTEXT* ctx = (NOTIFY_CONTEXT*)ctx_void; + DXGKRNL_INTERFACE* pDxgkInterface = ctx->pDxgkInterface; + pDxgkInterface->DxgkCbNotifyInterrupt(pDxgkInterface->DeviceHandle, ctx->interrupt); + if (ctx->triggerDpc) { + pDxgkInterface->DxgkCbQueueDpc(pDxgkInterface->DeviceHandle); + } + + return TRUE; +} + +NTSTATUS VioGpuAdapter::NotifyInterrupt(DXGKARGCB_NOTIFY_INTERRUPT_DATA* interruptData, BOOL triggerDpc) { + NOTIFY_CONTEXT notify; + notify.pDxgkInterface = &m_DxgkInterface; + notify.interrupt = interruptData; + notify.triggerDpc = triggerDpc; + BOOLEAN bRet; + return m_DxgkInterface.DxgkCbSynchronizeExecution( + m_DxgkInterface.DeviceHandle, + NotifyRoutine, + ¬ify, + 0, + &bRet + ); +} + + +virtio_gpu_formats ColorFormat(UINT format) +{ + switch (format) + { + case D3DDDIFMT_A8R8G8B8: + return VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM; + case D3DDDIFMT_X8R8G8B8: + return VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; + case D3DDDIFMT_A8B8G8R8: + return VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM; + case D3DDDIFMT_X8B8G8R8: + return VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM; + } + DbgPrint(TRACE_LEVEL_ERROR, ("---> %s Unsupported color format %d\n", __FUNCTION__, format)); + return VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM; +} + + +PAGED_CODE_SEG_BEGIN + + +VioGpuAdapter::VioGpuAdapter(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pPhysicalDeviceObject), +m_MonitorPowerState(PowerDeviceD0), +m_AdapterPowerState(PowerDeviceD0), +commander(this), vidpn(this) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + *((UINT*)&m_Flags) = 0; + RtlZeroMemory(&m_DxgkInterface, sizeof(m_DxgkInterface)); + RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo)); + RtlZeroMemory(&m_PointerShape, sizeof(m_PointerShape)); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + RtlZeroMemory(&m_VioDev, sizeof(m_VioDev)); + m_Id = g_InstanceId++; + m_PendingWorks = 0; + KeInitializeEvent(&m_ConfigUpdateEvent, + SynchronizationEvent, + FALSE); + m_bStopWorkThread = FALSE; + m_pWorkThread = NULL; + m_ResolutionEvent = NULL; + m_ResolutionEventHandle = NULL; + m_u32NumCapsets = 0; + m_u32NumScanouts = 0; +} + +VioGpuAdapter::~VioGpuAdapter(void) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + CloseResolutionEvent(); + VioGpuAdapterClose(); + HWClose(); + m_Id = 0; +} + +BOOLEAN VioGpuAdapter::CheckHardware() +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_GRAPHICS_DRIVER_MISMATCH; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PCI_COMMON_HEADER Header = { 0 }; + ULONG BytesRead; + + Status = m_DxgkInterface.DxgkCbReadDeviceSpace(m_DxgkInterface.DeviceHandle, + DXGK_WHICHSPACE_CONFIG, + &Header, + 0, + sizeof(Header), + &BytesRead); + + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbReadDeviceSpace failed with status 0x%X\n", Status)); + return FALSE; + } + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s VendorId = 0x%04X DeviceId = 0x%04X\n", __FUNCTION__, Header.VendorID, Header.DeviceID)); + if (Header.VendorID == REDHAT_PCI_VENDOR_ID && + Header.DeviceID == 0x1050) + { + SetVgaDevice(Header.SubClass == PCI_SUBCLASS_VID_VGA_CTLR); + return TRUE; + } + + return FALSE; +} + +#pragma warning(disable: 4702) +NTSTATUS VioGpuAdapter::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, + _In_ DXGKRNL_INTERFACE* pDxgkInterface, + _Out_ ULONG* pNumberOfViews, + _Out_ ULONG* pNumberOfChildren) +{ + PAGED_CODE(); + + NTSTATUS Status; + VIOGPU_ASSERT(pDxgkStartInfo != NULL); + VIOGPU_ASSERT(pDxgkInterface != NULL); + VIOGPU_ASSERT(pNumberOfViews != NULL); + VIOGPU_ASSERT(pNumberOfChildren != NULL); + RtlCopyMemory(&m_DxgkInterface, pDxgkInterface, sizeof(m_DxgkInterface)); + + Status = m_DxgkInterface.DxgkCbGetDeviceInformation(m_DxgkInterface.DeviceHandle, &m_DeviceInfo); + if (!NT_SUCCESS(Status)) + { + VIOGPU_LOG_ASSERTION1("DxgkCbGetDeviceInformation failed with status 0x%X\n", + Status); + return Status; + } + + if (!CheckHardware()) + { + Status = STATUS_NO_MEMORY; + DbgPrint(TRACE_LEVEL_ERROR, ("StartDevice failed to allocate memory\n")); + return Status; + } + + Status = GetRegisterInfo(); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_WARNING, ("GetRegisterInfo failed with status 0x%X\n", Status)); + } + + Status = HWInit(m_DeviceInfo.TranslatedResourceList); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("HWInit failed with status 0x%X\n", Status)); + return Status; + } + + if (!AckFeature(VIRTIO_GPU_F_VIRGL)) { + DbgPrint(TRACE_LEVEL_ERROR, ("VioGpu3D cannot start because virgl is not enabled\n")); + return STATUS_UNSUCCESSFUL; + } + + Status = SetRegisterInfo(GetInstanceId(), 0); + if (!NT_SUCCESS(Status)) + { + VIOGPU_LOG_ASSERTION1("RegisterHWInfo failed with status 0x%X\n", + Status); + return Status; + } + + commander.Start(); + Status = vidpn.Start(pNumberOfViews, pNumberOfChildren); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("VioGpuaVidPN::Start failed with status 0x%X\n", Status)); + VioGpuDbgBreak(); + return STATUS_UNSUCCESSFUL; + } + + m_Flags.DriverStarted = TRUE; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuAdapter::StopDevice(VOID) +{ + PAGED_CODE(); + commander.Stop(); + + m_Flags.DriverStarted = FALSE; + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuAdapter::DispatchIoRequest(_In_ ULONG VidPnSourceId, + _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(VidPnSourceId); + UNREFERENCED_PARAMETER(pVideoRequestPacket); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s\n", __FUNCTION__)); + + return STATUS_SUCCESS; +} + +PCHAR +DbgDevicePowerString( + __in DEVICE_POWER_STATE Type +) +{ + PAGED_CODE(); + + switch (Type) + { + case PowerDeviceUnspecified: + return "PowerDeviceUnspecified"; + case PowerDeviceD0: + return "PowerDeviceD0"; + case PowerDeviceD1: + return "PowerDeviceD1"; + case PowerDeviceD2: + return "PowerDeviceD2"; + case PowerDeviceD3: + return "PowerDeviceD3"; + case PowerDeviceMaximum: + return "PowerDeviceMaximum"; + default: + return "UnKnown Device Power State"; + } +} + +PCHAR +DbgPowerActionString( + __in POWER_ACTION Type +) +{ + PAGED_CODE(); + + switch (Type) + { + case PowerActionNone: + return "PowerActionNone"; + case PowerActionReserved: + return "PowerActionReserved"; + case PowerActionSleep: + return "PowerActionSleep"; + case PowerActionHibernate: + return "PowerActionHibernate"; + case PowerActionShutdown: + return "PowerActionShutdown"; + case PowerActionShutdownReset: + return "PowerActionShutdownReset"; + case PowerActionShutdownOff: + return "PowerActionShutdownOff"; + case PowerActionWarmEject: + return "PowerActionWarmEject"; + default: + return "UnKnown Device Power State"; + } +} + +NTSTATUS VioGpuAdapter::SetPowerState(_In_ ULONG HardwareUid, + _In_ DEVICE_POWER_STATE DevicePowerState, + _In_ POWER_ACTION ActionType) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(ActionType); + + DbgPrint(TRACE_LEVEL_FATAL, ("---> %s HardwareUid = 0x%x ActionType = %s DevicePowerState = %s AdapterPowerState = %s\n", + __FUNCTION__, HardwareUid, DbgPowerActionString(ActionType), DbgDevicePowerString(DevicePowerState), DbgDevicePowerString(m_AdapterPowerState))); + + if (HardwareUid == DISPLAY_ADAPTER_HW_ID) + { + if (DevicePowerState == PowerDeviceD0) + { + vidpn.AcquirePostDisplayOwnership(); + + if (m_AdapterPowerState == PowerDeviceD3) + { + DXGKARG_SETVIDPNSOURCEVISIBILITY Visibility; + Visibility.VidPnSourceId = D3DDDI_ID_ALL; + Visibility.Visible = FALSE; + vidpn.SetVidPnSourceVisibility(&Visibility); + } + m_AdapterPowerState = DevicePowerState; + } + + + switch (DevicePowerState) + { + case PowerDeviceUnspecified: + case PowerDeviceD0: { + VioGpuAdapterInit(); + } break; + case PowerDeviceD1: + case PowerDeviceD2: + case PowerDeviceD3: { + vidpn.Powerdown(); + VioGpuAdapterClose(); + } break; + } + return STATUS_SUCCESS; + } + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuAdapter::QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, + _In_ ULONG ChildRelationsSize) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + VIOGPU_ASSERT(pChildRelations != NULL); + + ULONG ChildRelationsCount = (ChildRelationsSize / sizeof(DXGK_CHILD_DESCRIPTOR)) - 1; + VIOGPU_ASSERT(ChildRelationsCount <= MAX_CHILDREN); + + for (UINT ChildIndex = 0; ChildIndex < ChildRelationsCount; ++ChildIndex) + { + pChildRelations[ChildIndex].ChildDeviceType = TypeVideoOutput; + pChildRelations[ChildIndex].ChildCapabilities.HpdAwareness = IsVgaDevice() ? HpdAwarenessAlwaysConnected : HpdAwarenessInterruptible; + pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.InterfaceTechnology = IsVgaDevice() ? D3DKMDT_VOT_INTERNAL : D3DKMDT_VOT_HD15; + pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.MonitorOrientationAwareness = D3DKMDT_MOA_NONE; + pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.SupportsSdtvModes = FALSE; + pChildRelations[ChildIndex].AcpiUid = 0; + pChildRelations[ChildIndex].ChildUid = ChildIndex; + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuAdapter::QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus, + _In_ BOOLEAN NonDestructiveOnly) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + UNREFERENCED_PARAMETER(NonDestructiveOnly); + VIOGPU_ASSERT(pChildStatus != NULL); + VIOGPU_ASSERT(pChildStatus->ChildUid < MAX_CHILDREN); + + switch (pChildStatus->Type) + { + case StatusConnection: + { + pChildStatus->HotPlug.Connected = IsDriverActive(); + return STATUS_SUCCESS; + } + + case StatusRotation: + { + DbgPrint(TRACE_LEVEL_ERROR, ("Child status being queried for StatusRotation even though D3DKMDT_MOA_NONE was reported")); + return STATUS_INVALID_PARAMETER; + } + + default: + { + DbgPrint(TRACE_LEVEL_WARNING, ("Unknown pChildStatus->Type (0x%I64x) requested.", pChildStatus->Type)); + return STATUS_NOT_SUPPORTED; + } + } +} + +NTSTATUS VioGpuAdapter::QueryDeviceDescriptor(_In_ ULONG ChildUid, + _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + VIOGPU_ASSERT(pDeviceDescriptor != NULL); + VIOGPU_ASSERT(ChildUid < MAX_CHILDREN); + PBYTE edid = vidpn.GetEdidData(ChildUid); + + if (!edid) + { + return STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED; + } + else if (pDeviceDescriptor->DescriptorOffset < EDID_V1_BLOCK_SIZE) + { + ULONG len = min(pDeviceDescriptor->DescriptorLength, (EDID_V1_BLOCK_SIZE - pDeviceDescriptor->DescriptorOffset)); + RtlCopyMemory(pDeviceDescriptor->DescriptorBuffer, (edid + pDeviceDescriptor->DescriptorOffset), len); + pDeviceDescriptor->DescriptorLength = len; + return STATUS_SUCCESS; + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA; +} + +NTSTATUS VioGpuAdapter::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo) +{ + PAGED_CODE(); + + VIOGPU_ASSERT(pQueryAdapterInfo != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + switch (pQueryAdapterInfo->Type) + { + case DXGKQAITYPE_UMDRIVERPRIVATE: { + if (pQueryAdapterInfo->OutputDataSize < sizeof(VIOGPU_ADAPTERINFO)) { + DbgPrint(TRACE_LEVEL_ERROR, ("pQueryAdapterInfo->OutputDataSize (0x%u) is smaller than sizeof(VIOGPU_ADAPTERINFO) (0x%u)\n", pQueryAdapterInfo->OutputDataSize, sizeof(VIOGPU_ADAPTERINFO))) + return STATUS_BUFFER_TOO_SMALL; + } + VIOGPU_ADAPTERINFO* info = (VIOGPU_ADAPTERINFO*)pQueryAdapterInfo->pOutputData; + info->IamVioGPU = VIOGPU_IAM; + info->Flags.Supports3d = virtio_is_feature_enabled(m_u64HostFeatures, VIRTIO_GPU_F_VIRGL); + info->Flags.Reserved = 0; + info->SupportedCapsetIDs = m_supportedCapsetIDs; + return STATUS_SUCCESS; + } + case DXGKQAITYPE_DRIVERCAPS: + { + if (!pQueryAdapterInfo->OutputDataSize) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pQueryAdapterInfo->OutputDataSize (0x%u) is smaller than sizeof(DXGK_DRIVERCAPS) (0x%u)\n", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_DRIVERCAPS))); + return STATUS_BUFFER_TOO_SMALL; + } + + DXGK_DRIVERCAPS* pDriverCaps = (DXGK_DRIVERCAPS*)pQueryAdapterInfo->pOutputData; + DbgPrint(TRACE_LEVEL_ERROR, ("InterruptMessageNumber = %d, WDDMVersion = %d\n", + pDriverCaps->InterruptMessageNumber, pDriverCaps->WDDMVersion)); + RtlZeroMemory(pDriverCaps, pQueryAdapterInfo->OutputDataSize/*sizeof(DXGK_DRIVERCAPS)*/); + pDriverCaps->WDDMVersion = DXGKDDI_WDDMv1_3; + pDriverCaps->HighestAcceptableAddress.QuadPart = (ULONG64)-1; + + + pDriverCaps->FlipCaps.FlipOnVSyncMmIo = TRUE; + + pDriverCaps->MaxQueuedFlipOnVSync = 1; + + pDriverCaps->MemoryManagementCaps.SectionBackedPrimary = TRUE; + + pDriverCaps->SupportDirectFlip = 1; + pDriverCaps->SchedulingCaps.MultiEngineAware = 1; + pDriverCaps->SchedulingCaps.PreemptionAware = 1; + + pDriverCaps->GpuEngineTopology.NbAsymetricProcessingNodes = 1; + + pDriverCaps->SupportSmoothRotation = FALSE; + pDriverCaps->SupportNonVGA = IsVgaDevice(); + + //if (IsPointerEnabled()) { + // pDriverCaps->MaxPointerWidth = POINTER_SIZE; + // pDriverCaps->MaxPointerHeight = POINTER_SIZE; + // pDriverCaps->PointerCaps.Value = 0; + // pDriverCaps->PointerCaps.Color = 1; + //} + + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s Driver caps return\n", __FUNCTION__)); + return STATUS_SUCCESS; + } + case DXGKQAITYPE_QUERYSEGMENT3: + { + if (pQueryAdapterInfo->OutputDataSize < sizeof(DXGK_QUERYSEGMENTOUT3)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pQueryAdapterInfo->OutputDataSize (0x%u) is smaller than sizeof(DXGK_QUERYSEGMENTOUT) (0x%u)\n", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_QUERYSEGMENTOUT))); + return STATUS_BUFFER_TOO_SMALL; + } + + DbgPrint(TRACE_LEVEL_ERROR, ("QUERY SEG\n")); + DXGK_QUERYSEGMENTOUT3* pSegmentInfo = (DXGK_QUERYSEGMENTOUT3*)pQueryAdapterInfo->pOutputData; + if (!pSegmentInfo[0].pSegmentDescriptor) + { + pSegmentInfo->NbSegment = 1; + } + else { + DXGK_SEGMENTDESCRIPTOR3* pSegmentDesc = pSegmentInfo->pSegmentDescriptor; + memset(&pSegmentDesc[0], 0, sizeof(pSegmentDesc[0])); + + pSegmentInfo->PagingBufferPrivateDataSize = 0; + + pSegmentInfo->PagingBufferSegmentId = 1; + pSegmentInfo->PagingBufferSize = 10 * PAGE_SIZE; + + // + // Fill out aperture segment descriptor + // + memset(&pSegmentDesc[0], 0, sizeof(pSegmentDesc[0])); + + pSegmentDesc[0].BaseAddress.QuadPart = 0xC0000000; + pSegmentDesc[0].Flags.Aperture = TRUE; + pSegmentDesc[0].Flags.CacheCoherent = TRUE; + //pSegmentDesc[0].CpuTranslatedAddress.QuadPart = 0xFFFFFFFE00000000; + + pSegmentDesc[0].Flags.CpuVisible = FALSE; + + + //pSegmentDesc[0].Flags.DirectFlip = TRUE; + pSegmentDesc[0].Size = 256 * 1024 * 4096; + pSegmentDesc[0].CommitLimit = 256 * 1024 * 4096; + + pSegmentDesc[0].Flags.DirectFlip = TRUE; + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s Requested segments\n", __FUNCTION__)); + return STATUS_SUCCESS; + } + + default: + { + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s unknown type %d\n", __FUNCTION__, pQueryAdapterInfo->Type)); + return STATUS_NOT_SUPPORTED; + } + } +} + +NTSTATUS VioGpuAdapter::Escape(_In_ CONST DXGKARG_ESCAPE* pEscape) +{ + PAGED_CODE(); + + VIOGPU_ASSERT(pEscape != NULL); + + DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s Flags = %d\n", __FUNCTION__, pEscape->Flags.Value)); + PAGED_CODE(); + PVIOGPU_ESCAPE pVioGpuEscape = (PVIOGPU_ESCAPE)pEscape->pPrivateDriverData; + NTSTATUS status = STATUS_SUCCESS; + UNREFERENCED_PARAMETER(pVioGpuEscape); + + UINT size = pEscape->PrivateDriverDataSize; + if (size < sizeof(PVIOGPU_ESCAPE)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("%s buffer too small %d, should be at least %d\n", __FUNCTION__, + pEscape->PrivateDriverDataSize, size)); + return STATUS_INVALID_BUFFER_SIZE; + } + + switch (pVioGpuEscape->Type) { + case VIOGPU_GET_DEVICE_ID: { + CreateResolutionEvent(); + size = sizeof(ULONG); + if (pVioGpuEscape->DataLength < size) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s buffer too small %d, should be at least %d\n", __FUNCTION__, + pVioGpuEscape->DataLength, size)); + return STATUS_INVALID_BUFFER_SIZE; + } + pVioGpuEscape->Id = m_Id; + break; + } + case VIOGPU_GET_CUSTOM_RESOLUTION: { + size = sizeof(VIOGPU_DISP_MODE); + if (pVioGpuEscape->DataLength < size) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s buffer too small %d, should be at least %d\n", __FUNCTION__, + pVioGpuEscape->DataLength, size)); + return STATUS_INVALID_BUFFER_SIZE; + } + vidpn.EscapeCustomResoulution(&pVioGpuEscape->Resolution); + break; + } + case VIOGPU_GET_CAPS: { + size = sizeof(VIOGPU_CAPSET_REQ); + if (pVioGpuEscape->DataLength < size) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s buffer too small %d, should be at least %d\n", __FUNCTION__, + pVioGpuEscape->DataLength, size)); + return STATUS_INVALID_BUFFER_SIZE; + } + + if (!(m_supportedCapsetIDs & (1ull << pVioGpuEscape->Capset.CapsetId))) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s capset id is not supported\n", __FUNCTION__)); + return STATUS_INVALID_PARAMETER_1; + } + CAPSET_INFO* pCapsetInfo = &m_capsetInfos[pVioGpuEscape->Capset.CapsetId]; + if (pCapsetInfo->max_version < pVioGpuEscape->Capset.Version) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s capset version is too low\n", __FUNCTION__)); + return STATUS_INVALID_PARAMETER_2; + }; + + PGPU_VBUFFER vbuf; + ctrlQueue.AskCapset(&vbuf, pVioGpuEscape->Capset.CapsetId, pCapsetInfo->max_size, pVioGpuEscape->Capset.Version); + UCHAR* buf = ((PGPU_RESP_CAPSET)vbuf->resp_buf)->capset_data; + ULONG to_copy = min(pVioGpuEscape->Capset.Size, pCapsetInfo->max_size); + __try { + memcpy(pVioGpuEscape->Capset.Capset, buf, to_copy); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + DbgPrint(TRACE_LEVEL_FATAL, ("Failed to copy")); + status = STATUS_INVALID_PARAMETER; + } + ctrlQueue.ReleaseBuffer(vbuf); + + break; + } + case VIOGPU_RES_INFO: { + size = sizeof(VIOGPU_RES_INFO_REQ); + if (pVioGpuEscape->DataLength < size) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s buffer too small %d, should be at least %d\n", __FUNCTION__, + pVioGpuEscape->DataLength, size)); + return STATUS_INVALID_BUFFER_SIZE; + } + VioGpuAllocation* allocation = AllocationFromHandle(pVioGpuEscape->ResourceInfo.ResHandle); + if(allocation == NULL) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s ivalid handle\n", __FUNCTION__)); + return STATUS_INVALID_PARAMETER; + } + + status = allocation->EscapeResourceInfo(&pVioGpuEscape->ResourceInfo); + + break; + } + case VIOGPU_RES_BUSY: { + size = sizeof(VIOGPU_RES_BUSY_REQ); + if (pVioGpuEscape->DataLength < size) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s buffer too small %d, should be at least %d\n", __FUNCTION__, + pVioGpuEscape->DataLength, size)); + return STATUS_INVALID_BUFFER_SIZE; + } + VioGpuAllocation* allocation = AllocationFromHandle(pVioGpuEscape->ResourceBusy.ResHandle); + if (allocation == NULL) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s ivalid handle\n", __FUNCTION__)); + return STATUS_INVALID_PARAMETER; + } + status = allocation->EscapeResourceBusy(&pVioGpuEscape->ResourceBusy); + + break; + } + case VIOGPU_CTX_INIT: { + size = sizeof(VIOGPU_CTX_INIT_REQ); + if (pVioGpuEscape->DataLength < size) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s buffer too small %d, should be at least %d\n", __FUNCTION__, + pVioGpuEscape->DataLength, size)); + return STATUS_INVALID_BUFFER_SIZE; + } + VioGpuDevice* context = reinterpret_cast(pEscape->hDevice); + if (context == NULL) { + DbgPrint(TRACE_LEVEL_ERROR, ("%s no hDdevice(context) supplied\n", __FUNCTION__)); + return STATUS_INVALID_PARAMETER; + } + context->Init(&pVioGpuEscape->CtxInit); + break; + } + + default: + DbgPrint(TRACE_LEVEL_ERROR, ("%s: invalid Escape type 0x%x\n", __FUNCTION__, pVioGpuEscape->Type)); + status = STATUS_INVALID_PARAMETER; + } + + return status; +} + +NTSTATUS VioGpuAdapter::QueryInterface(_In_ CONST PQUERY_INTERFACE pQueryInterface) +{ + PAGED_CODE(); + + VIOGPU_ASSERT(pQueryInterface != NULL); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s Version = %d\n", __FUNCTION__, pQueryInterface->Version)); + + return STATUS_NOT_SUPPORTED; +} + +NTSTATUS VioGpuAdapter::StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo) +{ + PAGED_CODE(); + + + VIOGPU_ASSERT(TargetId < MAX_CHILDREN); +//FIXME!!! + if (m_MonitorPowerState > PowerDeviceD0) + { + SetPowerState(TargetId, PowerDeviceD0, PowerActionNone); + } + vidpn.ReleasePostDisplayOwnership(TargetId, pDisplayInfo); + return StopDevice(); +} + +PAGED_CODE_SEG_END + +// +// Non-Paged Code +// +#pragma code_seg(push) +#pragma code_seg() + +VOID VioGpuAdapter::DpcRoutine(VOID) +{ + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + PGPU_VBUFFER pvbuf = NULL; + UINT len = 0; + ULONG reason; + while ((reason = InterlockedExchange((PLONG)&m_PendingWorks, 0)) != 0) + { + if ((reason & ISR_REASON_DISPLAY)) { + while ((pvbuf = ctrlQueue.DequeueBuffer(&len)) != NULL) + { + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s ctrlQueue pvbuf = %p len = %d\n", __FUNCTION__, pvbuf, len)); + PGPU_CTRL_HDR pcmd = (PGPU_CTRL_HDR)pvbuf->buf; + PGPU_CTRL_HDR resp = (PGPU_CTRL_HDR)pvbuf->resp_buf; + + if (resp->type >= 0x1200) { + DbgPrint(TRACE_LEVEL_FATAL, ("!!!!! Command failed %d", resp->type)); + } + if (resp->type != VIRTIO_GPU_RESP_OK_NODATA) + { + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s type = %xlu flags = %lu fence_id = %llu ctx_id = %lu cmd_type = %lu\n", + __FUNCTION__, resp->type, resp->flags, resp->fence_id, resp->ctx_id, pcmd->type)); + } + if (pvbuf->complete_cb != NULL) + { + pvbuf->complete_cb(pvbuf->complete_ctx); + } + if (!pvbuf->no_auto_release) { + ctrlQueue.ReleaseBuffer(pvbuf); + } + }; + } + if ((reason & ISR_REASON_CURSOR)) { + while ((pvbuf = m_CursorQueue.DequeueCursor(&len)) != NULL) + { + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s m_CursorQueue pvbuf = %p len = %u\n", __FUNCTION__, pvbuf, len)); + m_CursorQueue.ReleaseBuffer(pvbuf); + }; + } + if (reason & ISR_REASON_CHANGE) { + DbgPrint(TRACE_LEVEL_FATAL, ("---> %s ConfigChanged\n", __FUNCTION__)); + KeSetEvent(&m_ConfigUpdateEvent, IO_NO_INCREMENT, FALSE); + } + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + m_DxgkInterface.DxgkCbNotifyDpc((HANDLE)m_DxgkInterface.DeviceHandle); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +VOID VioGpuAdapter::ResetDevice(VOID) +{ + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); +} + +#pragma code_seg(pop) // End Non-Paged Code + +PAGED_CODE_SEG_BEGIN +NTSTATUS VioGpuAdapter::WriteRegistryString(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue) +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + ANSI_STRING AnsiStrValue; + UNICODE_STRING UnicodeStrValue; + UNICODE_STRING UnicodeStrValueName; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName); + + RtlInitAnsiString(&AnsiStrValue, pszValue); + Status = RtlAnsiStringToUnicodeString(&UnicodeStrValue, &AnsiStrValue, TRUE); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("RtlAnsiStringToUnicodeString failed with Status: 0x%X\n", Status)); + return Status; + } + + Status = ZwSetValueKey(DevInstRegKeyHandle, + &UnicodeStrValueName, + 0, + REG_SZ, + UnicodeStrValue.Buffer, + UnicodeStrValue.MaximumLength); + + RtlFreeUnicodeString(&UnicodeStrValue); + + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("ZwSetValueKey failed with Status: 0x%X\n", Status)); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS VioGpuAdapter::WriteRegistryDWORD(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PDWORD pdwValue) +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING UnicodeStrValueName; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName); + + Status = ZwSetValueKey(DevInstRegKeyHandle, + &UnicodeStrValueName, + 0, + REG_DWORD, + pdwValue, + sizeof(DWORD)); + + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("ZwSetValueKey failed with Status: 0x%X\n", Status)); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS VioGpuAdapter::ReadRegistryDWORD(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _Inout_ PDWORD pdwValue) +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING UnicodeStrValueName; + ULONG ulRes; + UCHAR Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)]; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName); + + Status = ZwQueryValueKey(DevInstRegKeyHandle, + &UnicodeStrValueName, + KeyValuePartialInformation, + Buf, + sizeof(Buf), + &ulRes); + + if (Status == STATUS_SUCCESS) + { + if (((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Type == REG_DWORD && + (((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->DataLength == sizeof(DWORD))) + { + ASSERT(Buf.Info.DataLength == sizeof(DWORD)); + *pdwValue = *((PDWORD) &(((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data)); + } + else + { + Status = STATUS_INVALID_PARAMETER; + VioGpuDbgBreak(); + } + } + + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("ZwQueryValueKey failed with Status: 0x%X\n", Status)); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS VioGpuAdapter::SetRegisterInfo(_In_ ULONG Id, _In_ DWORD MemSize) +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PCSTR StrHWInfoChipType = "QEMU VIRTIO GPU"; + PCSTR StrHWInfoDacType = "VIRTIO GPU"; + PCSTR StrHWInfoAdapterString = "VIRTIO GPU"; + PCSTR StrHWInfoBiosString = "SEABIOS VIRTIO GPU"; + + HANDLE DevInstRegKeyHandle; + Status = IoOpenDeviceRegistryKey(m_pPhysicalDevice, PLUGPLAY_REGKEY_DRIVER, KEY_SET_VALUE, &DevInstRegKeyHandle); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("IoOpenDeviceRegistryKey failed for PDO: 0x%p, Status: 0x%X", m_pPhysicalDevice, Status)); + return Status; + } + + do { + Status = WriteRegistryString(DevInstRegKeyHandle, L"HardwareInformation.ChipType", StrHWInfoChipType); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("WriteRegistryString failed for ChipType with Status: 0x%X", Status)); + break; + } + + Status = WriteRegistryString(DevInstRegKeyHandle, L"HardwareInformation.DacType", StrHWInfoDacType); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("WriteRegistryString failed DacType with Status: 0x%X", Status)); + break; + } + + Status = WriteRegistryString(DevInstRegKeyHandle, L"HardwareInformation.AdapterString", StrHWInfoAdapterString); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("WriteRegistryString failed for AdapterString with Status: 0x%X", Status)); + break; + } + + Status = WriteRegistryString(DevInstRegKeyHandle, L"HardwareInformation.BiosString", StrHWInfoBiosString); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("WriteRegistryString failed for BiosString with Status: 0x%X", Status)); + break; + } + + DWORD MemorySize = MemSize; + Status = WriteRegistryDWORD(DevInstRegKeyHandle, L"HardwareInformation.MemorySize", &MemorySize); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("WriteRegistryDWORD failed for MemorySize with Status: 0x%X", Status)); + break; + } + + DWORD DeviceId = Id; + Status = WriteRegistryDWORD(DevInstRegKeyHandle, L"VioGpuAdapterID", &DeviceId); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("WriteRegistryDWORD failed for VioGpuAdapterID with Status: 0x%X", Status)); + } + } while (0); + + ZwClose(DevInstRegKeyHandle); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS VioGpuAdapter::GetRegisterInfo(void) +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + HANDLE DevInstRegKeyHandle; + Status = IoOpenDeviceRegistryKey(m_pPhysicalDevice, PLUGPLAY_REGKEY_DRIVER, KEY_READ, &DevInstRegKeyHandle); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("IoOpenDeviceRegistryKey failed for PDO: 0x%p, Status: 0x%X", m_pPhysicalDevice, Status)); + return Status; + } + + DWORD value = 0; + Status = ReadRegistryDWORD(DevInstRegKeyHandle, L"HWCursor", &value); + if (NT_SUCCESS(Status)) + { + SetPointerEnabled(!!value); + } + + value = 0; + Status = ReadRegistryDWORD(DevInstRegKeyHandle, L"FlexResolution", &value); + if (NT_SUCCESS(Status)) + { + SetFlexResolution(!!value); + } + + value = 0; + Status = ReadRegistryDWORD(DevInstRegKeyHandle, L"UsePhysicalMemory", &value); + if (!NT_SUCCESS(Status)) + { + SetUsePhysicalMemory(!!value); + } + + ZwClose(DevInstRegKeyHandle); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} +PAGED_CODE_SEG_END + +PAGED_CODE_SEG_BEGIN + + + +NTSTATUS VioGpuAdapter::VioGpuAdapterInit() +{ + PAGED_CODE(); + NTSTATUS status = STATUS_SUCCESS; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + if (IsHardwareInit()) { + DbgPrint(TRACE_LEVEL_FATAL, ("Already Initialized\n")); + VioGpuDbgBreak(); + return status; + } + status = VirtIoDeviceInit(); + if (!NT_SUCCESS(status)) { + DbgPrint(TRACE_LEVEL_FATAL, ("Failed to initialize virtio device, error %x\n", status)); + VioGpuDbgBreak(); + return status; + } + + m_u64HostFeatures = virtio_get_features(&m_VioDev); + m_u64GuestFeatures = 0; + do + { + struct virtqueue *vqs[2]; + if (!AckFeature(VIRTIO_F_VERSION_1)) + { + status = STATUS_UNSUCCESSFUL; + break; + } +#if (NTDDI_VERSION >= NTDDI_WIN10) + AckFeature(VIRTIO_F_ACCESS_PLATFORM); +#endif + + + if (!AckFeature(VIRTIO_F_VERSION_1)) + { + status = STATUS_UNSUCCESSFUL; + break; + } + + status = virtio_set_features(&m_VioDev, m_u64GuestFeatures); + if (!NT_SUCCESS(status)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("%s virtio_set_features failed with %x\n", __FUNCTION__, status)); + VioGpuDbgBreak(); + break; + } + + status = virtio_find_queues( + &m_VioDev, + 2, + vqs); + if (!NT_SUCCESS(status)) { + DbgPrint(TRACE_LEVEL_FATAL, ("virtio_find_queues failed with error %x\n", status)); + VioGpuDbgBreak(); + break; + } + + if (!ctrlQueue.Init(&m_VioDev, vqs[0], 0) || + !m_CursorQueue.Init(&m_VioDev, vqs[1], 1)) { + DbgPrint(TRACE_LEVEL_FATAL, ("Failed to initialize virtio queues\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + VioGpuDbgBreak(); + break; + } + + virtio_get_config(&m_VioDev, FIELD_OFFSET(GPU_CONFIG, num_scanouts), + &m_u32NumScanouts, sizeof(m_u32NumScanouts)); + + virtio_get_config(&m_VioDev, FIELD_OFFSET(GPU_CONFIG, num_capsets), + &m_u32NumCapsets, sizeof(m_u32NumCapsets)); + } while (0); + if (status == STATUS_SUCCESS) + { + virtio_device_ready(&m_VioDev); + SetHardwareInit(TRUE); + } + else + { + virtio_add_status(&m_VioDev, VIRTIO_CONFIG_S_FAILED); + VioGpuDbgBreak(); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + return status; +} + +void VioGpuAdapter::VioGpuAdapterClose() +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_FATAL, ("---> %s\n", __FUNCTION__)); + + if (IsHardwareInit()) + { + SetHardwareInit(FALSE); + ctrlQueue.DisableInterrupt(); + m_CursorQueue.DisableInterrupt(); + virtio_device_reset(&m_VioDev); + virtio_delete_queues(&m_VioDev); + ctrlQueue.Close(); + m_CursorQueue.Close(); + virtio_device_shutdown(&m_VioDev); + } + DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s\n", __FUNCTION__)); +} + + +BOOLEAN VioGpuAdapter::AckFeature(UINT64 Feature) +{ + PAGED_CODE(); + + if (virtio_is_feature_enabled(m_u64HostFeatures, Feature)) + { + virtio_feature_enable(m_u64GuestFeatures, Feature); + return TRUE; + } + return FALSE; +} + + +NTSTATUS VioGpuAdapter::VirtIoDeviceInit() +{ + PAGED_CODE(); + + return virtio_device_initialize( + &m_VioDev, + &VioGpuSystemOps, + reinterpret_cast(this), + m_PciResources.IsMSIEnabled()); +} + + + +VOID VioGpuAdapter::CreateResolutionEvent(VOID) +{ + PAGED_CODE(); + + if (m_ResolutionEvent != NULL && + m_ResolutionEventHandle != NULL) + { + return; + } + DECLARE_UNICODE_STRING_SIZE(DeviceNumber, 10); + DECLARE_UNICODE_STRING_SIZE(EventName, 256); + + RtlIntegerToUnicodeString(m_Id, 10, &DeviceNumber); + NTSTATUS status = RtlUnicodeStringPrintf( + &EventName, + L"%ws%ws%ws", + BASE_NAMED_OBJECTS, + RESOLUTION_EVENT_NAME, + DeviceNumber.Buffer + ); + if (!NT_SUCCESS(status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("RtlUnicodeStringPrintf failed 0x%x\n", status)); + return; + } + m_ResolutionEvent = IoCreateNotificationEvent(&EventName, &m_ResolutionEventHandle); + if (m_ResolutionEvent == NULL) { + DbgPrint(TRACE_LEVEL_FATAL, ("<--> %s\n", __FUNCTION__)); + return; + } + KeClearEvent(m_ResolutionEvent); + ObReferenceObject(m_ResolutionEvent); +} + +VOID VioGpuAdapter::NotifyResolutionEvent(VOID) +{ + PAGED_CODE(); + + if (m_ResolutionEvent != NULL) { + DbgPrint(TRACE_LEVEL_ERROR, ("NotifyResolutionEvent\n")); + KeSetEvent(m_ResolutionEvent, IO_NO_INCREMENT, FALSE); + KeClearEvent(m_ResolutionEvent); + } +} + +VOID VioGpuAdapter::CloseResolutionEvent(VOID) +{ + PAGED_CODE(); + + if (m_ResolutionEventHandle != NULL) { + ZwClose(m_ResolutionEventHandle); + m_ResolutionEventHandle = NULL; + } + + if (m_ResolutionEvent != NULL) { + ObDereferenceObject(m_ResolutionEvent); + m_ResolutionEvent = NULL; + } +} + +NTSTATUS VioGpuAdapter::HWInit(PCM_RESOURCE_LIST pResList) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + HANDLE threadHandle = 0; + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + UINT size = 0; + do + { + if (!m_PciResources.Init(GetDxgkInterface(), pResList)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("Incomplete resources\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + VioGpuDbgBreak(); + break; + } + + status = VioGpuAdapterInit(); + if (!NT_SUCCESS(status)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("%s Failed initialize adapter %x\n", __FUNCTION__, status)); + VioGpuDbgBreak(); + break; + } + + + + size = ctrlQueue.QueryAllocation() + m_CursorQueue.QueryAllocation(); + DbgPrint(TRACE_LEVEL_FATAL, ("%s size %d\n", __FUNCTION__, size)); + ASSERT(size); + + if (!m_GpuBuf.Init(size)) { + DbgPrint(TRACE_LEVEL_FATAL, ("Failed to initialize buffers\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + VioGpuDbgBreak(); + break; + } + + ctrlQueue.SetGpuBuf(&m_GpuBuf); + m_CursorQueue.SetGpuBuf(&m_GpuBuf); + + if (!resourceIdr.Init(1)) { + DbgPrint(TRACE_LEVEL_FATAL, ("Failed to initialize id generator\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + VioGpuDbgBreak(); + break; + } + + if (!ctxIdr.Init(1)) { + DbgPrint(TRACE_LEVEL_FATAL, ("Failed to initialize id generator\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + VioGpuDbgBreak(); + break; + } + + m_supportedCapsetIDs = 0; + for (UINT32 i = 0; i < m_u32NumCapsets; i++) { + PGPU_VBUFFER vbuf = NULL; + + ctrlQueue.AskCapsetInfo(&vbuf, i); + PGPU_RESP_CAPSET_INFO resp = (PGPU_RESP_CAPSET_INFO)vbuf->resp_buf; + ULONG capset_id = resp->capset_id; + if (capset_id > 63 || capset_id <= 0) continue; // Invalid capset id, capsets ids are in range from 1 to 63 per specification + m_capsetInfos[capset_id].id = capset_id; + m_capsetInfos[capset_id].max_size = resp->capset_max_size; + m_capsetInfos[capset_id].max_version = resp->capset_max_version; + m_supportedCapsetIDs |= 1ull << capset_id; + DbgPrint(TRACE_LEVEL_FATAL, ("CAPSET INFO %d id: %d; version: %d; size: %d\n", i, capset_id, resp->capset_max_size, resp->capset_max_version)); + } + + } while (0); +//FIXME!!! exit if the block above failed + + status = PsCreateSystemThread(&threadHandle, + (ACCESS_MASK)0, + NULL, + (HANDLE)0, + NULL, + VioGpuAdapter::ThreadWork, + this); + + if (!NT_SUCCESS(status)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("%s failed to create system thread, status %x\n", __FUNCTION__, status)); + VioGpuDbgBreak(); + return status; + } + ObReferenceObjectByHandle(threadHandle, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + (PVOID*)(&m_pWorkThread), + NULL); + + ZwClose(threadHandle); + + PHYSICAL_ADDRESS fb_pa = m_PciResources.GetPciBar(0)->GetPA(); + UINT fb_size = (UINT)m_PciResources.GetPciBar(0)->GetSize(); + + //FIXME +#if NTDDI_VERSION > NTDDI_WINBLUE + UINT req_size = 0x1000000; +#else + UINT req_size = 0x800000; +#endif + + if (!IsUsePhysicalMemory() || + fb_pa.QuadPart == 0 || + fb_size < req_size) { + fb_pa.QuadPart = 0LL; + fb_size = max (req_size, fb_size); + } + + if (!frameSegment.Init(fb_size, &fb_pa)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("%s failed to allocate FB memory segment\n", __FUNCTION__)); + status = STATUS_INSUFFICIENT_RESOURCES; + VioGpuDbgBreak(); + return status; + } + + return status; +} + +NTSTATUS VioGpuAdapter::HWClose(void) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + SetHardwareInit(FALSE); + + LARGE_INTEGER timeout = { 0 }; + timeout.QuadPart = Int32x32To64(1000, -10000); + + m_bStopWorkThread = TRUE; + KeSetEvent(&m_ConfigUpdateEvent, IO_NO_INCREMENT, FALSE); + + if (KeWaitForSingleObject(m_pWorkThread, + Executive, + KernelMode, + FALSE, + &timeout) == STATUS_TIMEOUT) { + DbgPrint(TRACE_LEVEL_FATAL, ("---> Failed to exit the worker thread\n")); + VioGpuDbgBreak(); + } + + ObDereferenceObject(m_pWorkThread); + + frameSegment.Close(); + + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); + + return STATUS_SUCCESS; +} + +BOOLEAN FindUpdateRect( + _In_ ULONG NumMoves, + _In_ D3DKMT_MOVE_RECT* pMoves, + _In_ ULONG NumDirtyRects, + _In_ PRECT pDirtyRect, + _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation, + _Out_ PRECT pUpdateRect) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Rotation); + BOOLEAN updated = FALSE; + + if (pUpdateRect == NULL) return FALSE; + + if (NumMoves == 0 && NumDirtyRects == 0) { + pUpdateRect->bottom = 0; + pUpdateRect->left = 0; + pUpdateRect->right = 0; + pUpdateRect->top = 0; + } + + for (ULONG i = 0; i < NumMoves; i++) + { + PRECT pRect = &pMoves[i].DestRect; + if (!updated) + { + *pUpdateRect = *pRect; + updated = TRUE; + } + else + { + pUpdateRect->bottom = max(pRect->bottom, pUpdateRect->bottom); + pUpdateRect->left = min(pRect->left, pUpdateRect->left); + pUpdateRect->right = max(pRect->right, pUpdateRect->right); + pUpdateRect->top = min(pRect->top, pUpdateRect->top); + } + } + for (ULONG i = 0; i < NumDirtyRects; i++) + { + PRECT pRect = &pDirtyRect[i]; + if (!updated) + { + *pUpdateRect = *pRect; + updated = TRUE; + } + else + { + pUpdateRect->bottom = max(pRect->bottom, pUpdateRect->bottom); + pUpdateRect->left = min(pRect->left, pUpdateRect->left); + pUpdateRect->right = max(pRect->right, pUpdateRect->right); + pUpdateRect->top = min(pRect->top, pUpdateRect->top); + } + } + if (Rotation == D3DKMDT_VPPR_ROTATE90 || Rotation == D3DKMDT_VPPR_ROTATE270) + { + } + return updated; +} + + + +NTSTATUS VioGpuAdapter::UpdateChildStatus(BOOLEAN connect) +{ + PAGED_CODE(); + NTSTATUS Status(STATUS_SUCCESS); + DXGK_CHILD_STATUS ChildStatus; + PDXGKRNL_INTERFACE pDXGKInterface(GetDxgkInterface()); + + RtlZeroMemory(&ChildStatus, sizeof(ChildStatus)); + + ChildStatus.Type = StatusConnection; + ChildStatus.ChildUid = 0; + ChildStatus.HotPlug.Connected = connect; + Status = pDXGKInterface->DxgkCbIndicateChildStatus(pDXGKInterface->DeviceHandle, &ChildStatus); + if (Status != STATUS_SUCCESS) + { + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s DxgkCbIndicateChildStatus failed with status %x\n ", __FUNCTION__, Status)); + } + return Status; +} + + + +PAGED_CODE_SEG_END + + + +BOOLEAN VioGpuAdapter::InterruptRoutine(_In_ ULONG MessageNumber) +{ + if (!IsHardwareInit()) return FALSE; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s MessageNumber = %d\n", __FUNCTION__, MessageNumber)); + BOOLEAN serviced = TRUE; + ULONG intReason = 0; + //return FALSE; + if (m_PciResources.IsMSIEnabled()) + { + switch (MessageNumber) { + case 0: + intReason = ISR_REASON_CHANGE; + break; + case 1: + intReason = ISR_REASON_DISPLAY; + break; + case 2: + intReason = ISR_REASON_CURSOR; + break; + default: + serviced = FALSE; + DbgPrint(TRACE_LEVEL_FATAL, ("---> %s Unknown Interrupt Reason MessageNumber%d\n", __FUNCTION__, MessageNumber)); + } + } + else { + UNREFERENCED_PARAMETER(MessageNumber); + UCHAR isrstat = virtio_read_isr_status(&m_VioDev); + + switch (isrstat) { + case 1: + intReason = (ISR_REASON_DISPLAY | ISR_REASON_CURSOR); + break; + case 3: + intReason = ISR_REASON_CHANGE; + break; + default: + serviced = FALSE; + } + } + + if (serviced) { + InterlockedOr((PLONG)&m_PendingWorks, intReason); + m_DxgkInterface.DxgkCbQueueDpc(m_DxgkInterface.DeviceHandle); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + return serviced; +} + +void VioGpuAdapter::ThreadWork(_In_ PVOID Context) +{ + VioGpuAdapter* pdev = reinterpret_cast(Context); + pdev->ThreadWorkRoutine(); +} + +void VioGpuAdapter::ThreadWorkRoutine(void) +{ + KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); + + for (;;) + { + KeWaitForSingleObject(&m_ConfigUpdateEvent, + Executive, + KernelMode, + FALSE, + NULL); + + if (m_bStopWorkThread) { + PsTerminateSystemThread(STATUS_SUCCESS); + break; + } + + ConfigChanged(); + NotifyResolutionEvent(); + } +} + +void VioGpuAdapter::ConfigChanged(void) +{ + DbgPrint(TRACE_LEVEL_FATAL, ("<--> %s\n", __FUNCTION__)); + UINT32 events_read, events_clear = 0; + virtio_get_config(&m_VioDev, FIELD_OFFSET(GPU_CONFIG, events_read), + &events_read, sizeof(m_u32NumScanouts)); + if (events_read & VIRTIO_GPU_EVENT_DISPLAY) { + vidpn.GetDisplayInfo(); + events_clear |= VIRTIO_GPU_EVENT_DISPLAY; + virtio_set_config(&m_VioDev, FIELD_OFFSET(GPU_CONFIG, events_clear), + &events_clear, sizeof(m_u32NumScanouts)); + // UpdateChildStatus(FALSE); + // ProcessEdid(); + UpdateChildStatus(TRUE); + } +} + +VioGpuAllocation* VioGpuAdapter::AllocationFromHandle(D3DKMT_HANDLE handle) { + DXGKARGCB_GETHANDLEDATA getHandleData; + getHandleData.hObject = handle; + getHandleData.Type = DXGK_HANDLE_ALLOCATION; + getHandleData.Flags.DeviceSpecific = 0; + return reinterpret_cast(m_DxgkInterface.DxgkCbGetHandleData(&getHandleData)); +} + +VioGpuResource* VioGpuAdapter::ResourceFromHandle(D3DKMT_HANDLE handle) { + DXGKARGCB_GETHANDLEDATA getHandleData; + getHandleData.hObject = handle; + getHandleData.Type = DXGK_HANDLE_RESOURCE; + getHandleData.Flags.DeviceSpecific = 0; + return reinterpret_cast(m_DxgkInterface.DxgkCbGetHandleData(&getHandleData)); +} \ No newline at end of file diff --git a/viogpu/viogpu3d/viogpu_adapter.h b/viogpu/viogpu3d/viogpu_adapter.h new file mode 100644 index 000000000..8864fb105 --- /dev/null +++ b/viogpu/viogpu3d/viogpu_adapter.h @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2019-2020 Red Hat, Inc. + * + * Written By: Vadim Rozenfeld + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met : + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and / or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of their contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#include "helper.h" +#include "viogpu_allocation.h" +#include +#include + +#pragma pack(push) +#pragma pack(1) +typedef struct +{ + UINT DriverStarted : 1; + UINT HardwareInit : 1; + UINT PointerEnabled : 1; + UINT VgaDevice : 1; + UINT FlexResolution : 1; + UINT UsePhysicalMemory : 1; + UINT Unused : 26; +} DRIVER_STATUS_FLAG; + +#pragma pack(pop) + + +struct CAPSET_INFO { + ULONG max_version; + ULONG max_size; + ULONG id; +}; + +virtio_gpu_formats ColorFormat(UINT format); + +class VioGpuAdapter: IVioGpuPCI { +public: + VioGpuCommander commander; + VioGpuVidPN vidpn; + VioGpuIdr resourceIdr; + VioGpuIdr ctxIdr; + CtrlQueue ctrlQueue; + + VioGpuMemSegment frameSegment; + + UINT64 m_u64HostFeatures; + UINT64 m_u64GuestFeatures; + UINT32 m_u32NumCapsets; + UINT32 m_u32NumScanouts; + UINT64 m_supportedCapsetIDs; + + +private: + DEVICE_OBJECT* m_pPhysicalDevice; + DXGKRNL_INTERFACE m_DxgkInterface; + DXGK_DEVICE_INFO m_DeviceInfo; + + DEVICE_POWER_STATE m_MonitorPowerState; + DEVICE_POWER_STATE m_AdapterPowerState; + DRIVER_STATUS_FLAG m_Flags; + + DXGKARG_SETPOINTERSHAPE m_PointerShape; + + VirtIODevice m_VioDev; + CPciResources m_PciResources; + + CrsrQueue m_CursorQueue; + VioGpuBuf m_GpuBuf; + volatile ULONG m_PendingWorks; + KEVENT m_ConfigUpdateEvent; + PETHREAD m_pWorkThread; + BOOLEAN m_bStopWorkThread; + PKEVENT m_ResolutionEvent; + HANDLE m_ResolutionEventHandle; + + VioGpuObj* m_pCursorBuf; + VioGpuMemSegment m_CursorSegment; + + ULONG m_Id; + CAPSET_INFO m_capsetInfos[VIRTIO_GPU_MAX_CAPSET_ID + 1]; + +public: + VioGpuAdapter(_In_ DEVICE_OBJECT* pPhysicalDeviceObject); + ~VioGpuAdapter(void); +#pragma code_seg(push) +#pragma code_seg() + + BOOLEAN IsDriverActive() const + { + return m_Flags.DriverStarted; + } + BOOLEAN IsHardwareInit() const + { + return m_Flags.HardwareInit; + } + void SetHardwareInit(BOOLEAN init) + { + m_Flags.HardwareInit = init; + } + BOOLEAN IsPointerEnabled() const + { + return FALSE; + //return m_Flags.PointerEnabled; + } + void SetPointerEnabled(BOOLEAN Enabled) + { + m_Flags.PointerEnabled = Enabled; + } + BOOLEAN IsVgaDevice(void) const + { +#ifdef RENDER_ONLY + return FALSE; +#else + return m_Flags.VgaDevice; +#endif + } + void SetVgaDevice(BOOLEAN Vga) + { + m_Flags.VgaDevice = Vga; + } + BOOLEAN IsFlexResolution(void) const + { + return m_Flags.FlexResolution; + } + void SetFlexResolution(BOOLEAN FlexRes) + { + m_Flags.FlexResolution = FlexRes; + } + BOOLEAN IsUsePhysicalMemory() const + { + return m_Flags.UsePhysicalMemory; + } + void SetUsePhysicalMemory(BOOLEAN enable) + { + m_Flags.UsePhysicalMemory = enable; + } +#pragma code_seg(pop) + + NTSTATUS StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo, + _In_ DXGKRNL_INTERFACE* pDxgkInterface, + _Out_ ULONG* pNumberOfViews, + _Out_ ULONG* pNumberOfChildren); + NTSTATUS StopDevice(VOID); + VOID ResetDevice(VOID); + NTSTATUS DispatchIoRequest(_In_ ULONG VidPnSourceId, + _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket); + NTSTATUS SetPowerState(_In_ ULONG HardwareUid, + _In_ DEVICE_POWER_STATE DevicePowerState, + _In_ POWER_ACTION ActionType); + NTSTATUS QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations, + _In_ ULONG ChildRelationsSize); + NTSTATUS QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus, + _In_ BOOLEAN NonDestructiveOnly); + NTSTATUS QueryDeviceDescriptor(_In_ ULONG ChildUid, + _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor); + BOOLEAN InterruptRoutine(_In_ ULONG MessageNumber); + VOID DpcRoutine(VOID); + NTSTATUS QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo); + NTSTATUS Escape(_In_ CONST DXGKARG_ESCAPE* pEscape); + NTSTATUS QueryInterface(_In_ CONST PQUERY_INTERFACE QueryInterface); + NTSTATUS StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo); + PDXGKRNL_INTERFACE GetDxgkInterface(void) { return &m_DxgkInterface; } + NTSTATUS NotifyInterrupt(DXGKARGCB_NOTIFY_INTERRUPT_DATA* interruptData, BOOL triggerDpc); + + CPciResources* GetPciResources(void) { return &m_PciResources; } + BOOLEAN IsMSIEnabled() { return m_PciResources.IsMSIEnabled(); } + + VioGpuAllocation* AllocationFromHandle(D3DKMT_HANDLE handle); + VioGpuResource* ResourceFromHandle(D3DKMT_HANDLE handle); + + PHYSICAL_ADDRESS GetFrameBufferPA(void) { return m_PciResources.GetPciBar(0)->GetPA(); } + +private: + BOOLEAN CheckHardware(); + NTSTATUS WriteRegistryString(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue); + NTSTATUS WriteRegistryDWORD(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PDWORD pdwValue); + NTSTATUS ReadRegistryDWORD(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _Inout_ PDWORD pdwValue); + NTSTATUS SetRegisterInfo(_In_ ULONG Id, _In_ DWORD MemSize); + NTSTATUS GetRegisterInfo(void); + + NTSTATUS HWInit(PCM_RESOURCE_LIST pResList); + NTSTATUS HWClose(void); + + ULONG GetInstanceId(void) { return m_Id; } + + + NTSTATUS VioGpuAdapterInit(); + void VioGpuAdapterClose(void); + NTSTATUS VirtIoDeviceInit(void); + BOOLEAN AckFeature(UINT64 Feature); + + void static ThreadWork(_In_ PVOID Context); + void ThreadWorkRoutine(void); + + void ConfigChanged(void); + + VOID CreateResolutionEvent(VOID); + VOID NotifyResolutionEvent(VOID); + VOID CloseResolutionEvent(VOID); + + NTSTATUS UpdateChildStatus(BOOLEAN connect); + + + NTSTATUS SetPowerState(DXGK_DEVICE_INFO* pDeviceInfo, DEVICE_POWER_STATE DevicePowerState, CURRENT_MODE* pCurrentMode); + BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber); + VOID DpcRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface); + + UINT64 RequestParameter(ULONG parmeter); +}; diff --git a/viogpu/viogpu3d/viogpu_allocation.cpp b/viogpu/viogpu3d/viogpu_allocation.cpp new file mode 100644 index 000000000..e46460756 --- /dev/null +++ b/viogpu/viogpu3d/viogpu_allocation.cpp @@ -0,0 +1,354 @@ +#include "baseobj.h" +#include "bitops.h" +#include "viogpum.h" +#include "viogpu_allocation.h" +#include "viogpu_adapter.h" + +VioGpuAllocation::VioGpuAllocation(VioGpuAdapter *adapter, VIOGPU_RESOURCE_OPTIONS* options) +{ + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + m_adapter = adapter; + m_Id = m_adapter->resourceIdr.GetId(); + memcpy(&m_options, options, sizeof(VIOGPU_RESOURCE_OPTIONS)); + + //m_adapter->ctrlQueue.CreateResource(m_Id, m_options.format, m_options.width, m_options.height); + m_adapter->ctrlQueue.CreateResource3D(m_Id, options); + + m_pMDL = NULL; + m_pageCount = 0; + m_pageOffset = 0; + m_DxPhysicalAddress = 0; + + KeInitializeEvent(&m_busyNotification, NotificationEvent, TRUE); + m_busy = 0; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s res_id=%d\n", __FUNCTION__, m_Id)); +} + +VioGpuAllocation::~VioGpuAllocation(void) +{ + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s res_id=%d\n", __FUNCTION__, m_Id)); + m_adapter->ctrlQueue.DestroyResource(m_Id); + m_adapter->resourceIdr.PutId(m_Id); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +void VioGpuAllocation::AttachBacking(MDL* pMDL, size_t pageCount, size_t pageOffset) { + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s res_id=%d\n", __FUNCTION__, m_Id)); + + m_pMDL = pMDL; + m_pageCount = pageCount; + m_pageOffset = pageOffset; + + + GPU_MEM_ENTRY* ents = new(NonPagedPoolNx) GPU_MEM_ENTRY[pageCount]; + + for (UINT i = 0; i < pageCount; i++) + { + ents[i].addr = MmGetMdlPfnArray(pMDL)[pageOffset + i] * PAGE_SIZE; + ents[i].length = PAGE_SIZE; + ents[i].padding = 0; + } + + m_adapter->ctrlQueue.AttachBacking(m_Id, ents, (UINT)pageCount); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +void VioGpuAllocation::DetachBacking() { + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s res_id=%d\n", __FUNCTION__, m_Id)); + + m_pMDL = NULL; + m_pageCount = 0; + m_pageOffset = 0; + + m_adapter->ctrlQueue.DetachBacking(m_Id); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + +PAGED_CODE_SEG_BEGIN + +void VioGpuAllocation::MarkBusy() { + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s res_id=%d\n", __FUNCTION__, m_Id)); + + InterlockedIncrement(&m_busy); + KeClearEvent(&m_busyNotification); +} + +void VioGpuAllocation::UnmarkBusy() { + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s res_id=%d\n", __FUNCTION__, m_Id)); + + if (InterlockedDecrement(&m_busy) == 0) { + KeSetEvent(&m_busyNotification, IO_NO_INCREMENT, FALSE); + } +} + + +D3DDDIFORMAT VioGpuToD3DDDIColorFormat(virtio_gpu_formats format) +{ + PAGED_CODE(); + + switch (format) + { + case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: + return D3DDDIFMT_A8R8G8B8; + case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: + return D3DDDIFMT_X8R8G8B8; + case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: + return D3DDDIFMT_A8B8G8R8; + case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: + return D3DDDIFMT_X8B8G8R8; + } + DbgPrint(TRACE_LEVEL_ERROR, ("---> %s Unsupported color format %d\n", __FUNCTION__, format)); + return D3DDDIFMT_X8B8G8R8; +} + +void VioGpuAllocation::FlushToScreen(UINT scan_id) { + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s res_id=%d\n", __FUNCTION__, m_Id)); + + GPU_BOX box; + box.x = 0; + box.y = 0; + box.z = 0; + box.width = m_options.width; + box.height = m_options.height; + box.depth = 1; + + m_adapter->ctrlQueue.SetScanout(scan_id, m_Id, m_options.width, m_options.height, 0, 0); + m_adapter->ctrlQueue.ResFlush(m_Id, m_options.width, m_options.height, 0, 0); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s res_id=%d\n", __FUNCTION__, m_Id)); +} + +#define VIRGL_BIND_RENDER_TARGET (1 << 1) +#define VIRGL_BIND_SAMPLER_VIEW (1 << 3) +#define VIRGL_BIND_DISPLAY_TARGET (1 << 7) +#define VIRGL_BIND_DISPLAY_TARGET (1 << 7) +#define VIRGL_BIND_SCANOUT (1 << 18) + +NTSTATUS VioGpuAllocation::GetStandardAllocationDriverData(DXGKARG_GETSTANDARDALLOCATIONDRIVERDATA* pStandardAllocation) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_ERROR, ("---> %s type=%d\n", __FUNCTION__, pStandardAllocation->StandardAllocationType)); + + if (!pStandardAllocation->pResourcePrivateDriverData && !pStandardAllocation->pResourcePrivateDriverData) + { + pStandardAllocation->ResourcePrivateDriverDataSize = sizeof(VIOGPU_CREATE_RESOURCE_EXCHANGE); + pStandardAllocation->AllocationPrivateDriverDataSize = sizeof(VIOGPU_CREATE_ALLOCATION_EXCHANGE); + return STATUS_SUCCESS; + } + + VIOGPU_CREATE_ALLOCATION_EXCHANGE* allocationExchange = (VIOGPU_CREATE_ALLOCATION_EXCHANGE*)pStandardAllocation->pAllocationPrivateDriverData; + + allocationExchange->ResourceOptions.target = 2; + allocationExchange->ResourceOptions.format = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM; + allocationExchange->ResourceOptions.bind = VIRGL_BIND_RENDER_TARGET | VIRGL_BIND_SAMPLER_VIEW | VIRGL_BIND_DISPLAY_TARGET | VIRGL_BIND_SCANOUT; + + allocationExchange->ResourceOptions.width = 1024; + allocationExchange->ResourceOptions.height = 768; + allocationExchange->ResourceOptions.depth = 1; + + allocationExchange->ResourceOptions.array_size = 1; + allocationExchange->ResourceOptions.last_level = 0; + allocationExchange->ResourceOptions.nr_samples = 0; + allocationExchange->ResourceOptions.flags = 0; + + + switch (pStandardAllocation->StandardAllocationType) { + case D3DKMDT_STANDARDALLOCATION_SHAREDPRIMARYSURFACE: { + D3DKMDT_SHAREDPRIMARYSURFACEDATA* surfaceData = pStandardAllocation->pCreateSharedPrimarySurfaceData; + //[in] UINT Width; + //[in] UINT Height; + //[in] D3DDDIFORMAT Format; + + + allocationExchange->ResourceOptions.width = surfaceData->Width; + allocationExchange->ResourceOptions.height = surfaceData->Height; + allocationExchange->ResourceOptions.format = ColorFormat(surfaceData->Format); + allocationExchange->Size = (ULONGLONG)surfaceData->Width * (ULONGLONG)surfaceData->Height * 4; + + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s shared primary surface: width=%d, height=%d, format=%d\n", __FUNCTION__, surfaceData->Width, surfaceData->Height, surfaceData->Format)); + return STATUS_SUCCESS; + } + + case D3DKMDT_STANDARDALLOCATION_SHADOWSURFACE: { + D3DKMDT_SHADOWSURFACEDATA* surfaceData = pStandardAllocation->pCreateShadowSurfaceData; + //[in] UINT Width; + //[in] UINT Height; + //[in] D3DDDIFORMAT Format; + + + allocationExchange->ResourceOptions.width = surfaceData->Width; + allocationExchange->ResourceOptions.height = surfaceData->Height; + allocationExchange->ResourceOptions.format = ColorFormat(surfaceData->Format); + allocationExchange->Size = (ULONGLONG)surfaceData->Width * (ULONGLONG)surfaceData->Height * 4; + + allocationExchange->ResourceOptions.flags |= VIRGL_RESOURCE_FLAG_MAP_COHERENT; + + surfaceData->Pitch = surfaceData->Width * 4; + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s shadow surface: width=%d, height=%d, format=%d\n", __FUNCTION__, surfaceData->Width, surfaceData->Height, surfaceData->Format)); + return STATUS_SUCCESS; + } + + + case D3DKMDT_STANDARDALLOCATION_STAGINGSURFACE: { + D3DKMDT_STAGINGSURFACEDATA* surfaceData = pStandardAllocation->pCreateStagingSurfaceData; + //[in] UINT Width; + //[in] UINT Height; + //[in] D3DDDIFORMAT Format; + + + allocationExchange->ResourceOptions.width = surfaceData->Width; + allocationExchange->ResourceOptions.height = surfaceData->Height; + allocationExchange->ResourceOptions.format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM; + allocationExchange->Size = (ULONGLONG)surfaceData->Width * (ULONGLONG)surfaceData->Height * 4; + + allocationExchange->ResourceOptions.flags |= VIRGL_RESOURCE_FLAG_MAP_COHERENT; + + surfaceData->Pitch = surfaceData->Width * 4; + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s staging surface\n", __FUNCTION__)); + return STATUS_SUCCESS; + } + + default: { + DbgPrint(TRACE_LEVEL_FATAL, ("<--- Unknown standard allocation type \n")); + return STATUS_NOT_SUPPORTED; + } + } +} + + +NTSTATUS VioGpuAllocation::DxgkCreateAllocation(VioGpuAdapter* adapter, DXGKARG_CREATEALLOCATION* pCreateAllocation) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + DXGK_ALLOCATIONINFO* allocationInfo = pCreateAllocation->pAllocationInfo; + + if (max(allocationInfo->PrivateDriverDataSize, pCreateAllocation->PrivateDriverDataSize) < sizeof(VIOGPU_CREATE_ALLOCATION_EXCHANGE)) { + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s private driver data is too small\n", __FUNCTION__)); + return STATUS_INVALID_PARAMETER; + } + + VIOGPU_CREATE_ALLOCATION_EXCHANGE* resourceExchange = (VIOGPU_CREATE_ALLOCATION_EXCHANGE*)allocationInfo->pPrivateDriverData;; + if (pCreateAllocation->PrivateDriverDataSize > allocationInfo->PrivateDriverDataSize) { + resourceExchange = (VIOGPU_CREATE_ALLOCATION_EXCHANGE*)pCreateAllocation->pPrivateDriverData; + } + + + VioGpuAllocation* allocation = new(NonPagedPoolNx) VioGpuAllocation(adapter, &resourceExchange->ResourceOptions); + allocationInfo->hAllocation = allocation; + + if (pCreateAllocation->Flags.Resource) { + VioGpuResource* resource = new(NonPagedPoolNx) VioGpuResource(); + pCreateAllocation->hResource = resource; + } + + + allocationInfo->Alignment = 0; + allocationInfo->Size = (SIZE_T)resourceExchange->Size; + allocationInfo->PitchAlignedSize = 0; + allocationInfo->HintedBank.Value = 0; + allocationInfo->AllocationPriority = D3DDDI_ALLOCATIONPRIORITY_NORMAL; + allocationInfo->EvictionSegmentSet = 1; // don't use apperture for eviction + allocationInfo->Flags.Value = 0; + + allocationInfo->PreferredSegment.Value = 0; + allocationInfo->PreferredSegment.SegmentId0 = 1; + allocationInfo->PreferredSegment.Direction0 = 0; + + + allocationInfo->Flags.CpuVisible = TRUE; + + + allocationInfo->HintedBank.Value = 0; + allocationInfo->MaximumRenamingListLength = 0; + allocationInfo->pAllocationUsageHint = NULL; + allocationInfo->PhysicalAdapterIndex = 0; + allocationInfo->PitchAlignedSize = 0; + + allocationInfo->SupportedReadSegmentSet = 0b1; + allocationInfo->SupportedWriteSegmentSet = 0b1; + + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s res_id=%d size=%d\n", __FUNCTION__, allocation->GetId(), allocationInfo->Size)); + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuAllocation::DescribeAllocation(DXGKARG_DESCRIBEALLOCATION* pDescribeAllocation) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s res_id=%d\n", __FUNCTION__, m_Id)); + + pDescribeAllocation->Width = m_options.width; + pDescribeAllocation->Height = m_options.height; + pDescribeAllocation->PrivateDriverFormatAttribute = 0; + + pDescribeAllocation->Format = VioGpuToD3DDDIColorFormat((virtio_gpu_formats)m_options.format); + + // this values are RANDOM + pDescribeAllocation->MultisampleMethod.NumQualityLevels = 2; + pDescribeAllocation->MultisampleMethod.NumSamples = 2; + + pDescribeAllocation->RefreshRate.Numerator = 148500000; + pDescribeAllocation->RefreshRate.Denominator = 2475000; + + return STATUS_SUCCESS; +}; + +NTSTATUS VioGpuAllocation::MapApertureSegment(DXGKARG_BUILDPAGINGBUFFER* pBuildPagingBuffer) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s res_id=%d\n", __FUNCTION__, m_Id)); + + size_t pageCount = pBuildPagingBuffer->MapApertureSegment.NumberOfPages; + size_t mdlPageOffset = pBuildPagingBuffer->MapApertureSegment.MdlOffset; + + MDL* pMdl = pBuildPagingBuffer->MapApertureSegment.pMdl; + + AttachBacking(pMdl, pageCount, mdlPageOffset); + SetDxPhysicalAddress(pBuildPagingBuffer->MapApertureSegment.OffsetInPages * PAGE_SIZE); + + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuAllocation::UnmapApertureSegment(DXGKARG_BUILDPAGINGBUFFER* pBuildPagingBuffer) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s res_id=%d\n", __FUNCTION__, m_Id)); + + UNREFERENCED_PARAMETER(pBuildPagingBuffer); + DetachBacking(); + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuAllocation::EscapeResourceInfo(VIOGPU_RES_INFO_REQ* resInfo) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s res_id=%d\n", __FUNCTION__, m_Id)); + + resInfo->Id = m_Id; + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuAllocation::EscapeResourceBusy(VIOGPU_RES_BUSY_REQ* resBusy) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s res_id=%d\n", __FUNCTION__, m_Id)); + + while (resBusy->Wait && m_busy != 0) { + KeWaitForSingleObject(&m_busyNotification, UserRequest, KernelMode, FALSE, NULL); + + LARGE_INTEGER wait; + wait.QuadPart = -10LL; + KeDelayExecutionThread(KernelMode, FALSE, &wait); + } + + resBusy->IsBusy = m_busy != 0; + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG_END \ No newline at end of file diff --git a/viogpu/viogpu3d/viogpu_allocation.h b/viogpu/viogpu3d/viogpu_allocation.h new file mode 100644 index 000000000..6a1f42c86 --- /dev/null +++ b/viogpu/viogpu3d/viogpu_allocation.h @@ -0,0 +1,65 @@ +#pragma once +#include "helper.h" + +#define VIRGL_RESOURCE_FLAG_MAP_COHERENT (1 << 2) + +class VioGpuAdapter; + +class VioGpuResource +{ +public: +private: +}; + +class VioGpuAllocation { +public: + VioGpuAllocation(VioGpuAdapter* adapter, VIOGPU_RESOURCE_OPTIONS* options); + ~VioGpuAllocation(void); + + + UINT GetId(void) { return m_Id; } + + void MarkBusy(); + void UnmarkBusy(); + + void SetDxPhysicalAddress(size_t DxPhysicalAddress) { + m_DxPhysicalAddress = DxPhysicalAddress; + }; + size_t GetDxPhysicalAddress() { + return m_DxPhysicalAddress; + }; + + BOOL IsCoherent() { + return (m_options.flags & VIRGL_RESOURCE_FLAG_MAP_COHERENT) != 0; + } + + void AttachBacking(MDL* pMdl, size_t pageCount, size_t pageOffset); + void DetachBacking(); + + void FlushToScreen(UINT scan_id); + + static NTSTATUS GetStandardAllocationDriverData(DXGKARG_GETSTANDARDALLOCATIONDRIVERDATA* pStandardAllocation); + static NTSTATUS DxgkCreateAllocation(VioGpuAdapter* adapter, DXGKARG_CREATEALLOCATION* pCreateAllocation); + + NTSTATUS DescribeAllocation(DXGKARG_DESCRIBEALLOCATION* pDescribeAllocation); + NTSTATUS MapApertureSegment(DXGKARG_BUILDPAGINGBUFFER* pBuildPagingBuffer); + NTSTATUS UnmapApertureSegment(DXGKARG_BUILDPAGINGBUFFER* pBuildPagingBuffer); + + NTSTATUS EscapeResourceInfo(VIOGPU_RES_INFO_REQ *resInfo); + NTSTATUS EscapeResourceBusy(VIOGPU_RES_BUSY_REQ* resBusy); + +private: + VioGpuAdapter* m_adapter; + + VIOGPU_RESOURCE_OPTIONS m_options; + UINT m_Id; + + MDL* m_pMDL; + size_t m_pageCount; + size_t m_pageOffset; + + size_t m_DxPhysicalAddress; + + KEVENT m_busyNotification; + volatile LONG m_busy; +}; \ No newline at end of file diff --git a/viogpu/viogpu3d/viogpu_command.cpp b/viogpu/viogpu3d/viogpu_command.cpp new file mode 100644 index 000000000..2561b5be3 --- /dev/null +++ b/viogpu/viogpu3d/viogpu_command.cpp @@ -0,0 +1,391 @@ +#include "viogpu_command.h" +#include "viogpu_device.h" +#include "viogpu_adapter.h" +#include "baseobj.h" + +PAGED_CODE_SEG_BEGIN + +VioGpuCommand::VioGpuCommand(VioGpuAdapter* adapter) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s", __FUNCTION__)); + + m_pAdapter = adapter; + m_pCommander = &adapter->commander; + m_pContext = NULL; + + m_FenceId = 0; + m_pDmaBuffer = NULL; + m_pCommand = NULL; + m_pEnd = NULL; + + m_allocations = NULL; + m_allocationsLength = 0; + + list_entry.Blink = NULL; + list_entry.Flink = NULL; +}; + +void VioGpuCommand::Run() { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s", __FUNCTION__)); + + while (m_pCommand < m_pEnd) { + + VIOGPU_COMMAND_HDR* cmdHdr = (VIOGPU_COMMAND_HDR*)m_pCommand; + m_pCommand += sizeof(VIOGPU_COMMAND_HDR); + + void* cmdBody = m_pCommand; + m_pCommand += cmdHdr->size; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("%s fence_id=%d running command=%d", __FUNCTION__, m_FenceId, cmdHdr->type)); + + switch (cmdHdr->type) { + case VIOGPU_CMD_SUBMIT: { + m_pAdapter->ctrlQueue.SubmitCommand( + cmdBody, cmdHdr->size, m_pContext->GetId(), + VioGpuCommand::QueueRunningCb, this); + return; + } + + case VIOGPU_CMD_TRANSFER_TO_HOST: + case VIOGPU_CMD_TRANSFER_FROM_HOST: { + VIOGPU_TRANSFER_CMD* transferCmd = (VIOGPU_TRANSFER_CMD*)cmdBody; + + m_pAdapter->ctrlQueue.TransferHostCmd( + cmdHdr->type == VIOGPU_CMD_TRANSFER_TO_HOST, + m_pContext->GetId(), transferCmd, + VioGpuCommand::QueueRunningCb, this); + return; + } + + case VIOGPU_CMD_NOP: + default: + { + // DO NOTHING + break; + } + } + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("%s finished fence_id=%d", __FUNCTION__, m_FenceId)); + + DXGKARGCB_NOTIFY_INTERRUPT_DATA interrupt; + interrupt.InterruptType = DXGK_INTERRUPT_DMA_COMPLETED; + interrupt.DmaCompleted.SubmissionFenceId = m_FenceId; + interrupt.DmaCompleted.NodeOrdinal = 0; + interrupt.DmaCompleted.EngineOrdinal = 0; + m_pAdapter->NotifyInterrupt(&interrupt, true); + + if (m_allocations) { + for (UINT i = 0; i < m_allocationsLength; i++) { + if (m_allocations[i]) { + m_allocations[i]->UnmarkBusy(); + } + } + delete m_allocations; + } + + + m_pCommander->CommandFinished(); + + delete this; +} + +void VioGpuCommand::PrepareSubmit(const DXGKARG_SUBMITCOMMAND* pSubmitCommand) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s", __FUNCTION__)); + + m_FenceId = pSubmitCommand->SubmissionFenceId; + if (m_pDmaBuffer) { + m_pCommand = (char*)m_pDmaBuffer + pSubmitCommand->DmaBufferSubmissionStartOffset; + m_pEnd = (char*)m_pDmaBuffer + pSubmitCommand->DmaBufferSubmissionEndOffset; + } + m_pContext = reinterpret_cast(pSubmitCommand->hContext); +} + +void VioGpuCommand::AttachAllocations(DXGK_ALLOCATIONLIST* allocationList, UINT allocationListLength) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s", __FUNCTION__)); + + m_allocations = new(NonPagedPoolNx) VioGpuAllocation * [allocationListLength]; + m_allocationsLength = allocationListLength; + for (UINT i = 0; i < allocationListLength; i++) { + VioGpuDeviceAllocation* deviceAllocation = reinterpret_cast(allocationList[i].hDeviceSpecificAllocation); + if (deviceAllocation) { + m_allocations[i] = deviceAllocation->GetAllocation(); + m_allocations[i]->MarkBusy(); + } + else { + m_allocations[i] = NULL; + } + } +} + +PAGED_CODE_SEG_END + + + +#pragma code_seg(push) +#pragma code_seg() + +void VioGpuCommand::QueueRunning() { + m_pCommander->QueueRunning(this); +} + +void VioGpuCommand::QueueRunningCb(void *cmd) { + ((VioGpuCommand*)cmd)->QueueRunning(); +} + +#pragma code_seg(pop) + +PAGED_CODE_SEG_BEGIN + +VioGpuCommander::VioGpuCommander(VioGpuAdapter *pAdapter) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s", __FUNCTION__)); + + m_pAdapter = pAdapter; + m_bStopWorkThread = FALSE; + m_pWorkThread = NULL; + + KeInitializeEvent(&m_QueueEvent, + SynchronizationEvent, + FALSE); + + InitializeListHead(&m_SubmittedQueue); + InitializeListHead(&m_RunningQueue); + KeInitializeSpinLock(&m_Lock); + + m_running = 0; +} + +NTSTATUS VioGpuCommander::Start() { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s", __FUNCTION__)); + + HANDLE threadHandle = 0; + + NTSTATUS status = PsCreateSystemThread(&threadHandle, + (ACCESS_MASK)0, + NULL, + (HANDLE)0, + NULL, + VioGpuCommander::ThreadWork, + this); + + if (!NT_SUCCESS(status)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("%s failed to create command worker thread, status %x\n", __FUNCTION__, status)); + VioGpuDbgBreak(); + return status; + } + + ObReferenceObjectByHandle(threadHandle, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + (PVOID*)(&m_pWorkThread), + NULL); + + ZwClose(threadHandle); + + return status; +} + +void VioGpuCommander::Stop() { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s", __FUNCTION__)); + + LARGE_INTEGER timeout = { 0 }; + timeout.QuadPart = Int32x32To64(1000, -10000); + + m_bStopWorkThread = TRUE; + KeSetEvent(&m_QueueEvent, IO_NO_INCREMENT, FALSE); + + if (KeWaitForSingleObject(m_pWorkThread, + Executive, + KernelMode, + FALSE, + &timeout) == STATUS_TIMEOUT) { + DbgPrint(TRACE_LEVEL_FATAL, ("---> Failed to exit the worker thread\n")); + VioGpuDbgBreak(); + } +} + + +void VioGpuCommander::ThreadWork(PVOID Context) +{ + PAGED_CODE(); + + VioGpuCommander* pdev = reinterpret_cast(Context); + pdev->ThreadWorkRoutine(); +} + +void VioGpuCommander::ThreadWorkRoutine(void) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s", __FUNCTION__)); + + KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); + + for (;;) + { + KeWaitForSingleObject(&m_QueueEvent, + Executive, + KernelMode, + FALSE, + NULL); + + if (m_bStopWorkThread) { + PsTerminateSystemThread(STATUS_SUCCESS); + break; + } + + while (m_running < VIOGPU_MAX_RUNNING) { + VioGpuCommand* command = DequeueSubmitted(); + if (command == NULL) break; + QueueRunning(command); + m_running++; + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("%s Running command\n", __FUNCTION__)); + while (true) { + VioGpuCommand* command = DequeueRunning(); + if (command == NULL) break; + command->Run(); + } + } +} + +void VioGpuCommander::CommandFinished() { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s", __FUNCTION__)); + + m_running--; + KeSetEvent(&m_QueueEvent, IO_NO_INCREMENT, FALSE); +} + +NTSTATUS VioGpuCommander::Patch(const DXGKARG_PATCH* pPatch) { + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s \n", __FUNCTION__)); + + UNREFERENCED_PARAMETER(pPatch); + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG_END + +#pragma code_seg(push) +#pragma code_seg() +NTSTATUS VioGpuCommander::SubmitCommand(const DXGKARG_SUBMITCOMMAND* pSubmitCommand) +{ + VIOGPU_ASSERT(pSubmitCommand != NULL); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s fence_id=%d\n", __FUNCTION__, pSubmitCommand->SubmissionFenceId)); + + VioGpuCommand* cmd = NULL; + if (pSubmitCommand->pDmaBufferPrivateData) { + VioGpuCommand **priv = (VioGpuCommand**)pSubmitCommand->pDmaBufferPrivateData; + if (*priv != NULL) { + cmd = *priv; + } + } + + if (!cmd) { + cmd = new(NonPagedPoolNx) VioGpuCommand(m_pAdapter); + } + + cmd->PrepareSubmit(pSubmitCommand); + QueueSubmitted(cmd); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_saves_global_(OldIrql, Irql) +_IRQL_raises_(DISPATCH_LEVEL) +void VioGpuCommander::LockQueue(KIRQL* Irql) +{ + KIRQL SavedIrql = KeGetCurrentIrql(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s at IRQL %d\n", __FUNCTION__, SavedIrql)); + + if (SavedIrql < DISPATCH_LEVEL) { + KeAcquireSpinLock(&m_Lock, &SavedIrql); + } + else if (SavedIrql == DISPATCH_LEVEL) { + KeAcquireSpinLockAtDpcLevel(&m_Lock); + } + else { + VioGpuDbgBreak(); + } + *Irql = SavedIrql; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +_IRQL_requires_(DISPATCH_LEVEL) +_IRQL_restores_global_(OldIrql, Irql) +void VioGpuCommander::UnlockQueue(KIRQL Irql) +{ + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s at IRQL %d\n", __FUNCTION__, Irql)); + + if (Irql < DISPATCH_LEVEL) { + KeReleaseSpinLock(&m_Lock, Irql); + } + else { + KeReleaseSpinLockFromDpcLevel(&m_Lock); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +VioGpuCommand* VioGpuCommander::DequeueRunning() { + KIRQL oldIrql; + LockQueue(&oldIrql); + PLIST_ENTRY result = NULL; + if (!IsListEmpty(&m_RunningQueue)) { + result = RemoveHeadList(&m_RunningQueue); + } + UnlockQueue(oldIrql); + if (!result) + return NULL; + return CONTAINING_RECORD(result, VioGpuCommand, list_entry); +} + +void VioGpuCommander::QueueRunning(VioGpuCommand* cmd) { + KIRQL oldIrql; + LockQueue(&oldIrql); + InsertTailList(&m_RunningQueue, &cmd->list_entry); + UnlockQueue(oldIrql); + + KeSetEvent(&m_QueueEvent, IO_NO_INCREMENT, FALSE); +} + + +VioGpuCommand* VioGpuCommander::DequeueSubmitted() { + KIRQL oldIrql; + LockQueue(&oldIrql); + PLIST_ENTRY result = NULL; + if (!IsListEmpty(&m_SubmittedQueue)) { + result = RemoveHeadList(&m_SubmittedQueue); + } + UnlockQueue(oldIrql); + if (!result) + return NULL; + return CONTAINING_RECORD(result, VioGpuCommand, list_entry); +} + +void VioGpuCommander::QueueSubmitted(VioGpuCommand* cmd) { + KIRQL oldIrql; + LockQueue(&oldIrql); + InsertTailList(&m_SubmittedQueue, &cmd->list_entry); + UnlockQueue(oldIrql); + + KeSetEvent(&m_QueueEvent, IO_NO_INCREMENT, FALSE); +} + +#pragma code_seg(pop) \ No newline at end of file diff --git a/viogpu/viogpu3d/viogpu_command.h b/viogpu/viogpu3d/viogpu_command.h new file mode 100644 index 000000000..bbd0fe06c --- /dev/null +++ b/viogpu/viogpu3d/viogpu_command.h @@ -0,0 +1,88 @@ +#pragma once + +#include "helper.h" + +#define VIOGPU_MAX_RUNNING 1 + +class VioGpuAdapter; +class VioGpuDevice; +class VioGpuAllocation; +class VioGpuCommander; + +class VioGpuCommand { +public: + VioGpuCommand(VioGpuAdapter* adapter); + + void Run(); + + void PrepareSubmit(const DXGKARG_SUBMITCOMMAND* pSubmitCommand); + void QueueRunning(); + static void QueueRunningCb(void* cmd); + + void SetDmaBuf(char* pDmaBuffer) { + m_pDmaBuffer = pDmaBuffer; + } + + void AttachAllocations(DXGK_ALLOCATIONLIST* allocationList, UINT allocationListLength); + + LIST_ENTRY list_entry; +private: + VioGpuAdapter* m_pAdapter; + VioGpuCommander* m_pCommander; + VioGpuDevice* m_pContext; + + UINT m_FenceId; + + char* m_pDmaBuffer; + char* m_pCommand; + char* m_pEnd; + + VioGpuAllocation** m_allocations; + UINT m_allocationsLength; +}; + +class VioGpuCommander +{ +public: + VioGpuCommander(VioGpuAdapter* pAdapter); + + NTSTATUS Start(); + void Stop(); + + void CommandFinished(); + + NTSTATUS Patch(const DXGKARG_PATCH* pPatch); + NTSTATUS SubmitCommand(const DXGKARG_SUBMITCOMMAND* pSubmitCommand); + + _IRQL_requires_max_(DISPATCH_LEVEL) + _IRQL_saves_global_(OldIrql, Irql) + _IRQL_raises_(DISPATCH_LEVEL) + void LockQueue(KIRQL* Irql); + _IRQL_requires_(DISPATCH_LEVEL) + _IRQL_restores_global_(OldIrql, Irql) + void UnlockQueue(KIRQL Irql); + + VioGpuCommand* DequeueRunning(); + void QueueRunning(VioGpuCommand* cmd); + + VioGpuCommand* DequeueSubmitted(); + void QueueSubmitted(VioGpuCommand* cmd); + +private: + static void ThreadWork(PVOID Context); + void ThreadWorkRoutine(void); + + VioGpuAdapter* m_pAdapter; + + KEVENT m_QueueEvent; + PETHREAD m_pWorkThread; + BOOLEAN m_bStopWorkThread; + + LIST_ENTRY m_SubmittedQueue; + LIST_ENTRY m_RunningQueue; + + KSPIN_LOCK m_Lock; + + UINT m_running; +}; + diff --git a/viogpu/viogpu3d/viogpu_device.cpp b/viogpu/viogpu3d/viogpu_device.cpp new file mode 100644 index 000000000..24bfd3215 --- /dev/null +++ b/viogpu/viogpu3d/viogpu_device.cpp @@ -0,0 +1,342 @@ +#include "viogpu_device.h" +#include "viogpu_adapter.h" +#include "baseobj.h" + +PAGED_CODE_SEG_BEGIN + +VioGpuDevice::VioGpuDevice(VioGpuAdapter* pAdapter) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s", __FUNCTION__)); + + m_pAdapter = pAdapter; + m_id = pAdapter->ctxIdr.GetId(); + pAdapter->ctrlQueue.CreateCtx(m_id, 0); +} + +VioGpuDevice::~VioGpuDevice() { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s", __FUNCTION__)); + + m_pAdapter->ctrlQueue.DestroyCtx(m_id); + m_pAdapter->ctxIdr.PutId(m_id); +} + + +NTSTATUS VioGpuDevice::Init(VIOGPU_CTX_INIT_REQ* pOptions) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s", __FUNCTION__)); + + UINT context_init = 0; + + context_init |= pOptions->CapsetID; + + m_pAdapter->ctrlQueue.DestroyCtx(m_id); // Destroy old viogpu context + m_pAdapter->ctrlQueue.CreateCtx(m_id, context_init); + + return STATUS_SUCCESS; +} + + +// Used for blt command generation +#define VIRGL_CMD0(cmd, obj, len) ((cmd) | ((obj) << 8) | ((len) << 16)) +#define VIRGL_CCMD_RESOURCE_COPY_REGION 17 +#define VIRGL_CMD_RESOURCE_COPY_REGION_SIZE 13 + +NTSTATUS VioGpuDevice::GenerateBltPresent(DXGKARG_PRESENT* pPresent, VioGpuAllocation *src, VioGpuAllocation *dst) { + UCHAR* dmaBuf = (UCHAR*)pPresent->pDmaBuffer; + + // Calculate rect covering all SubRectx + RECT coverRect = pPresent->pDstSubRects[0]; + for (UINT i = 1; i < pPresent->SubRectCnt; i++) { + coverRect.top = min(coverRect.top, pPresent->pDstSubRects[i].top); + coverRect.left = min(coverRect.left, pPresent->pDstSubRects[i].left); + coverRect.right = min(coverRect.right, pPresent->pDstSubRects[i].right); + coverRect.bottom = min(coverRect.bottom, pPresent->pDstSubRects[i].bottom); + } + + INT dx = pPresent->SrcRect.left - pPresent->DstRect.left; + INT dy = pPresent->SrcRect.top - pPresent->DstRect.top; + + // If source requires coherency (staging or shadow surface) then emit transfer + if (src->IsCoherent()) { + VIOGPU_COMMAND_HDR* cmd_hdr = (VIOGPU_COMMAND_HDR*)dmaBuf; + cmd_hdr->type = VIOGPU_CMD_TRANSFER_TO_HOST; + cmd_hdr->size = sizeof(VIOGPU_TRANSFER_CMD); + dmaBuf += sizeof(VIOGPU_COMMAND_HDR); + + VIOGPU_TRANSFER_CMD* cmdBody = (VIOGPU_TRANSFER_CMD*)dmaBuf; + dmaBuf += sizeof(VIOGPU_TRANSFER_CMD); + + cmdBody->res_id = src->GetId(); + + cmdBody->box.x = coverRect.left + dx; + cmdBody->box.y = coverRect.top + dy; + cmdBody->box.z = 0; + cmdBody->box.width = coverRect.right - coverRect.left; + cmdBody->box.height = coverRect.bottom - coverRect.top; + cmdBody->box.depth = 1; + + cmdBody->layer_stride = 0; + cmdBody->stride = 0; + cmdBody->level = 0; + cmdBody->offset = 0; + } + + { + UINT sizeOfOneRect = 4 * (VIRGL_CMD_RESOURCE_COPY_REGION_SIZE + 1); + + // TODO: Support MultiPassOffset + UINT rectCnt = min(pPresent->SubRectCnt, (pPresent->DmaSize - 0x100) / sizeOfOneRect); + + VIOGPU_COMMAND_HDR* cmd_hdr = (VIOGPU_COMMAND_HDR*)dmaBuf; + cmd_hdr->type = VIOGPU_CMD_SUBMIT; + cmd_hdr->size = rectCnt * sizeOfOneRect; + dmaBuf += sizeof(VIOGPU_COMMAND_HDR); + + for (UINT i = 0; i < rectCnt; i++) { + UINT* cmdBody = (UINT*)dmaBuf; + dmaBuf += sizeOfOneRect; + + RECT rect = pPresent->pDstSubRects[i]; + + cmdBody[0] = VIRGL_CMD0(VIRGL_CCMD_RESOURCE_COPY_REGION, 0, VIRGL_CMD_RESOURCE_COPY_REGION_SIZE); + cmdBody[1] = dst->GetId(); + cmdBody[2] = 0; + cmdBody[3] = rect.left; + cmdBody[4] = rect.top; + cmdBody[5] = 0; + + cmdBody[6] = src->GetId(); + cmdBody[7] = 0; + cmdBody[8] = rect.left + dx; + cmdBody[9] = rect.top + dy; + cmdBody[10] = 0; + cmdBody[11] = rect.right - rect.left; + cmdBody[12] = rect.bottom - rect.top; + cmdBody[13] = 1; + } + } + + if(dst->IsCoherent()) { + VIOGPU_COMMAND_HDR* cmd_hdr = (VIOGPU_COMMAND_HDR*)dmaBuf; + cmd_hdr->type = VIOGPU_CMD_TRANSFER_FROM_HOST; + cmd_hdr->size = sizeof(VIOGPU_TRANSFER_CMD); + dmaBuf += sizeof(VIOGPU_COMMAND_HDR); + + VIOGPU_TRANSFER_CMD* cmdBody = (VIOGPU_TRANSFER_CMD*)dmaBuf; + dmaBuf += sizeof(VIOGPU_TRANSFER_CMD); + + cmdBody->res_id = dst->GetId(); + + cmdBody->box.x = coverRect.left; + cmdBody->box.y = coverRect.top; + cmdBody->box.z = 0; + cmdBody->box.width = coverRect.right - coverRect.left; + cmdBody->box.height = coverRect.bottom - coverRect.top; + cmdBody->box.depth = 1; + + cmdBody->layer_stride = 0; + cmdBody->stride = 0; + cmdBody->level = 0; + cmdBody->offset = 0; + } + + pPresent->pDmaBuffer = dmaBuf; + + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuDevice::Present(_Inout_ DXGKARG_PRESENT* pPresent) +{ + PAGED_CODE(); + + if (pPresent->Flags.Flip) return STATUS_SUCCESS; + + DbgPrint( + TRACE_LEVEL_VERBOSE, + ("<---> %s Flags=%s %s %s %s %s %s %s %s)\n", + __FUNCTION__, + pPresent->Flags.Blt ? "Blt" : "", + pPresent->Flags.ColorFill ? "ColorFill" : "", + pPresent->Flags.Flip ? "Flip" : "", + pPresent->Flags.FlipWithNoWait ? "FlipWithNoWait" : "", + pPresent->Flags.SrcColorKey ? "SrcColorKey" : "", + pPresent->Flags.DstColorKey ? "DstColorKey" : "", + pPresent->Flags.LinearToSrgb ? "LinearToSrgb" : "", + pPresent->Flags.Rotate ? "Rotate" : "")); + + VioGpuCommand* cmd = new(NonPagedPoolNx) VioGpuCommand(m_pAdapter); + if (pPresent->pDmaBuffer) { + VioGpuCommand** privateData = (VioGpuCommand**)pPresent->pDmaBufferPrivateData; + *privateData = cmd; + } + + cmd->SetDmaBuf((char*)pPresent->pDmaBuffer); + + DXGK_ALLOCATIONLIST* dxgk_src = &pPresent->pAllocationList[DXGK_PRESENT_SOURCE_INDEX]; + DXGK_ALLOCATIONLIST* dxgk_dst = &pPresent->pAllocationList[DXGK_PRESENT_DESTINATION_INDEX]; + + VioGpuAllocation* src = NULL; + VioGpuAllocation* dst = NULL;; + + if (dxgk_src->hDeviceSpecificAllocation != NULL) { + src = reinterpret_cast(dxgk_src->hDeviceSpecificAllocation)->GetAllocation(); + if (pPresent->pDmaBuffer) { + pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_DESTINATION_INDEX; + pPresent->pPatchLocationListOut->AllocationOffset = 0; + pPresent->pPatchLocationListOut->DriverId = 1; + pPresent->pPatchLocationListOut->SlotId = 1; + pPresent->pPatchLocationListOut->PatchOffset = 0; + pPresent->pPatchLocationListOut->SplitOffset = 0; + + pPresent->pPatchLocationListOut += 1; + } + } + + if (dxgk_dst != NULL) { + dst = reinterpret_cast(dxgk_dst->hDeviceSpecificAllocation)->GetAllocation(); + if (pPresent->pDmaBuffer) { + pPresent->pPatchLocationListOut->AllocationIndex = DXGK_PRESENT_SOURCE_INDEX; + pPresent->pPatchLocationListOut->AllocationOffset = 0; + pPresent->pPatchLocationListOut->DriverId = 2; + pPresent->pPatchLocationListOut->SlotId = 2; + pPresent->pPatchLocationListOut->PatchOffset = 0; + pPresent->pPatchLocationListOut->SplitOffset = 0; + + pPresent->pPatchLocationListOut += 1; + } + } + + if (pPresent->Flags.Blt) { + if (pPresent->pDmaBuffer && dst && src) { + GenerateBltPresent(pPresent, src, dst); + } + + } else { + if (pPresent->pDmaBuffer) { + VIOGPU_COMMAND_HDR* cmd_hdr = (VIOGPU_COMMAND_HDR*)pPresent->pDmaBuffer; + cmd_hdr->type = VIOGPU_CMD_NOP; + cmd_hdr->size = 0; + pPresent->pDmaBuffer = (char*)pPresent->pDmaBuffer + sizeof(VIOGPU_COMMAND_HDR); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s Unsupported PRESENT\n", __FUNCTION__)); + } + + + return STATUS_SUCCESS; +} + + +NTSTATUS VioGpuDevice::Render(DXGKARG_RENDER *pRender) { + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + char* pDmaBufStart = (char*)pRender->pDmaBuffer; + + __try + { + pRender->PatchLocationListOutSize = pRender->PatchLocationListInSize; + for (UINT i = 0; i < pRender->PatchLocationListOutSize; i++) { + pRender->pPatchLocationListOut->AllocationIndex = pRender->pPatchLocationListIn[i].AllocationIndex; + pRender->pPatchLocationListOut->AllocationOffset = 0; + pRender->pPatchLocationListOut->PatchOffset = 0; + pRender->pPatchLocationListOut->SplitOffset = 0; + pRender->pPatchLocationListOut->SlotId = i; + + pRender->pPatchLocationListOut++; + } + + unsigned char* dmaBuf = (unsigned char*)pRender->pDmaBuffer; + unsigned char* cmdBuf = (unsigned char*)pRender->pCommand; + unsigned char* endBuf = cmdBuf + pRender->CommandLength; + while (cmdBuf < endBuf) { + if (cmdBuf + sizeof(VIOGPU_COMMAND_HDR) > endBuf) { + return STATUS_INVALID_USER_BUFFER; + } + + memcpy(dmaBuf, cmdBuf, sizeof(VIOGPU_COMMAND_HDR)); + VIOGPU_COMMAND_HDR* cmdHdr = (VIOGPU_COMMAND_HDR*)dmaBuf; + cmdBuf += sizeof(VIOGPU_COMMAND_HDR); + dmaBuf += sizeof(VIOGPU_COMMAND_HDR); + + if (cmdBuf + cmdHdr->size > endBuf) { + return STATUS_INVALID_USER_BUFFER; + } + + // Copy command body + memcpy(dmaBuf, cmdBuf, cmdHdr->size); + dmaBuf += cmdHdr->size; + cmdBuf += cmdHdr->size; + } + pRender->pDmaBuffer = dmaBuf; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + DbgPrint(TRACE_LEVEL_FATAL, ("<---> %s Usermode copy exception", __FUNCTION__)); + return STATUS_INVALID_PARAMETER; + } + + + VioGpuCommand* cmd = new(NonPagedPoolNx) VioGpuCommand(m_pAdapter); + if (pRender->pDmaBuffer) { + VioGpuCommand** privateData = (VioGpuCommand**)pRender->pDmaBufferPrivateData; + *privateData = cmd; + } + cmd->SetDmaBuf(pDmaBufStart); + cmd->AttachAllocations(pRender->pAllocationList, pRender->AllocationListSize); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + return STATUS_SUCCESS; +}; + +NTSTATUS VioGpuDevice::OpenAllocation(_In_ CONST DXGKARG_OPENALLOCATION* pOpenAllocation) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + for (UINT i = 0; i < pOpenAllocation->NumAllocations; i++) + { + DXGK_OPENALLOCATIONINFO* openAllocationInfo = &pOpenAllocation->pOpenAllocation[i]; + VioGpuAllocation* allocation = m_pAdapter->AllocationFromHandle(openAllocationInfo->hAllocation); + openAllocationInfo->hDeviceSpecificAllocation = new (NonPagedPoolNx)VioGpuDeviceAllocation(this, allocation); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +CtrlQueue *VioGpuDevice::GetCtrlQueue() { + PAGED_CODE(); + + return &m_pAdapter->ctrlQueue; +} + + +VioGpuDeviceAllocation::VioGpuDeviceAllocation(VioGpuDevice *device, VioGpuAllocation* allocation) { + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s res_id=%d ctx_id=%d\n", __FUNCTION__, allocation->GetId(), device->GetId())); + + m_pAllocation = allocation; + m_pDevice = device; + + m_pDevice->GetCtrlQueue()->CtxResource(true, m_pDevice->GetId(), m_pAllocation->GetId()); +} + +VioGpuDeviceAllocation::~VioGpuDeviceAllocation() { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s res_id=%d ctx_id=%d\n", __FUNCTION__, m_pAllocation->GetId(), m_pDevice->GetId())); + + m_pDevice->GetCtrlQueue()->CtxResource(false, m_pDevice->GetId(), m_pAllocation->GetId()); +} + +VioGpuAllocation* VioGpuDeviceAllocation::GetAllocation() { + PAGED_CODE(); + + return m_pAllocation; +} + +PAGED_CODE_SEG_END \ No newline at end of file diff --git a/viogpu/viogpu3d/viogpu_device.h b/viogpu/viogpu3d/viogpu_device.h new file mode 100644 index 000000000..ddf9ab624 --- /dev/null +++ b/viogpu/viogpu3d/viogpu_device.h @@ -0,0 +1,44 @@ +#pragma once +#include "helper.h" +#include "viogpu_allocation.h" + +class VioGpuAdapter; + +// Class that represents DXGKRNL Context, often passed as hContext +class VioGpuDevice +{ +public: + VioGpuDevice(VioGpuAdapter* pAdapter); + ~VioGpuDevice(); + + + NTSTATUS Init(VIOGPU_CTX_INIT_REQ* pOptions); + NTSTATUS OpenAllocation(_In_ CONST DXGKARG_OPENALLOCATION* pOpenAllocation); + + NTSTATUS GenerateBltPresent(DXGKARG_PRESENT* pPresent, VioGpuAllocation* src, VioGpuAllocation* dst); + NTSTATUS Present(_Inout_ DXGKARG_PRESENT* pPresent); + NTSTATUS Render(DXGKARG_RENDER* pRender); + + ULONG GetId() { + return m_id; + } + + CtrlQueue* GetCtrlQueue(); + +private: + VioGpuAdapter* m_pAdapter; + ULONG m_id; +}; + +class VioGpuDeviceAllocation +{ +public: + VioGpuDeviceAllocation(VioGpuDevice *device, VioGpuAllocation* allocation); + ~VioGpuDeviceAllocation(); + + VioGpuAllocation* GetAllocation(); + +private: + VioGpuAllocation* m_pAllocation; + VioGpuDevice* m_pDevice; +}; \ No newline at end of file diff --git a/viogpu/viogpu3d/viogpu_vidpn.cpp b/viogpu/viogpu3d/viogpu_vidpn.cpp new file mode 100644 index 000000000..2d6025181 --- /dev/null +++ b/viogpu/viogpu3d/viogpu_vidpn.cpp @@ -0,0 +1,1803 @@ +#include "viogpu_vidpn.h" +#include "viogpu_adapter.h" +#include "bitops.h" +#include "baseobj.h" + +VIOGPU_DISP_MODE gpu_disp_modes[16] = +{ +#if NTDDI_VERSION > NTDDI_WINBLUE + {640, 480}, + {800, 600}, +#endif + {1024, 768}, + {1280, 1024}, + {1920, 1080}, +#if NTDDI_VERSION > NTDDI_WINBLUE + {2560, 1600}, +#endif + {0, 0}, +}; + + + +PAGED_CODE_SEG_BEGIN + +VioGpuVidPN::VioGpuVidPN(VioGpuAdapter* adapter) { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + m_pAdapter = adapter; + m_pDxgkInterface = adapter->GetDxgkInterface(); + + RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes)); + m_ModeInfo = NULL; + m_ModeCount = 0; + m_ModeNumbers = NULL; + m_CurrentMode = 0; + m_pFrameBuf = NULL; + + m_SystemDisplaySourceId = D3DDDI_ID_UNINITIALIZED; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); +} + +VioGpuVidPN::~VioGpuVidPN() { + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + DestroyFrameBufferObj(TRUE); + + delete[] m_ModeInfo; + delete[] m_ModeNumbers; + + m_CurrentMode = 0; + m_CustomMode = 0; + m_ModeCount = 0; + + m_ModeInfo = NULL; + m_ModeNumbers = NULL; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); +} + +NTSTATUS VioGpuVidPN::Start(ULONG* pNumberOfViews, ULONG* pNumberOfChildren) { + PAGED_CODE(); + + RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes)); + m_CurrentModes[0].DispInfo.TargetId = D3DDDI_ID_UNINITIALIZED; + + + NTSTATUS Status = GetModeList(&m_CurrentModes[0].DispInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("%s GetModeList failed with %x\n", __FUNCTION__, Status)); + VioGpuDbgBreak(); + } + + if (m_pAdapter->IsVgaDevice()) + { + Status = AcquirePostDisplayOwnership(); + if (!NT_SUCCESS(Status)) + { + return STATUS_UNSUCCESSFUL; + } + } + + DbgPrint(TRACE_LEVEL_FATAL, ("DxgkCbAcquirePostDisplayOwnership Width = %d Height = %d Pitch = %d ColorFormat = %d\n", + m_SystemDisplayInfo.Width, m_SystemDisplayInfo.Height, m_SystemDisplayInfo.Pitch, m_SystemDisplayInfo.ColorFormat)); + + if (m_SystemDisplayInfo.Width == 0) + { + m_SystemDisplayInfo.Width = NOM_WIDTH_SIZE; + m_SystemDisplayInfo.Height = NOM_HEIGHT_SIZE; + m_SystemDisplayInfo.ColorFormat = D3DDDIFMT_X8R8G8B8; + m_SystemDisplayInfo.Pitch = (BPPFromPixelFormat(m_SystemDisplayInfo.ColorFormat) / BITS_PER_BYTE) * m_SystemDisplayInfo.Width; + m_SystemDisplayInfo.TargetId = 0; + if (m_SystemDisplayInfo.PhysicAddress.QuadPart == 0LL) { + m_SystemDisplayInfo.PhysicAddress = m_pAdapter->GetFrameBufferPA(); + } + } + + m_CurrentModes[0].DispInfo.Width = max(MIN_WIDTH_SIZE, m_SystemDisplayInfo.Width); + m_CurrentModes[0].DispInfo.Height = max(MIN_HEIGHT_SIZE, m_SystemDisplayInfo.Height); + m_CurrentModes[0].DispInfo.ColorFormat = D3DDDIFMT_X8R8G8B8; + m_CurrentModes[0].DispInfo.Pitch = (BPPFromPixelFormat(m_CurrentModes[0].DispInfo.ColorFormat) / BITS_PER_BYTE) * m_CurrentModes[0].DispInfo.Width; + m_CurrentModes[0].DispInfo.TargetId = 0; + if (m_CurrentModes[0].DispInfo.PhysicAddress.QuadPart == 0LL && m_SystemDisplayInfo.PhysicAddress.QuadPart != 0LL) { + m_CurrentModes[0].DispInfo.PhysicAddress = m_SystemDisplayInfo.PhysicAddress; + } + + *pNumberOfViews = MAX_VIEWS; + *pNumberOfChildren = MAX_CHILDREN; + + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s ColorFormat = %d\n", __FUNCTION__, m_CurrentModes[0].DispInfo.ColorFormat)); + + + HANDLE threadHandle = 0; + m_shouldFlipStop = false; + Status = PsCreateSystemThread(&threadHandle, + (ACCESS_MASK)0, + NULL, + (HANDLE)0, + NULL, + VioGpuVidPN::FlipThread, + this); + + ObReferenceObjectByHandle(threadHandle, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + (PVOID*)(&m_pFlipThread), + NULL); + + ZwClose(threadHandle); + + return Status; +} + +NTSTATUS VioGpuVidPN::AcquirePostDisplayOwnership() { + NTSTATUS Status = m_pDxgkInterface->DxgkCbAcquirePostDisplayOwnership(m_pDxgkInterface->DeviceHandle, &m_SystemDisplayInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("DxgkCbAcquirePostDisplayOwnership failed with status 0x%X Width = %d\n", + Status, m_SystemDisplayInfo.Width)); + VioGpuDbgBreak(); + } + + return Status; +} + + +void VioGpuVidPN::ReleasePostDisplayOwnership(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, DXGK_DISPLAY_INFORMATION* pDisplayInfo) { + D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = FindSourceForTarget(TargetId, TRUE); + m_sourceAddress.QuadPart = 0; + + LARGE_INTEGER timeout = { 0 }; + timeout.QuadPart = Int32x32To64(1000, -10000); + + m_shouldFlipStop = TRUE; + + if (KeWaitForSingleObject(m_pFlipThread, + Executive, + KernelMode, + FALSE, + &timeout) == STATUS_TIMEOUT) { + DbgPrint(TRACE_LEVEL_FATAL, ("---> Failed to exit the flip thread\n")); + VioGpuDbgBreak(); + } + + ObDereferenceObject(m_pFlipThread); + + BlackOutScreen(&m_CurrentModes[SourceId]); + DestroyFrameBufferObj(TRUE); + + DbgPrint(TRACE_LEVEL_FATAL, ("StopDeviceAndReleasePostDisplayOwnership Width = %d Height = %d Pitch = %d ColorFormat = %dn", + m_SystemDisplayInfo.Width, m_SystemDisplayInfo.Height, m_SystemDisplayInfo.Pitch, m_SystemDisplayInfo.ColorFormat)); + + *pDisplayInfo = m_SystemDisplayInfo; + pDisplayInfo->TargetId = TargetId; + pDisplayInfo->AcpiId = m_CurrentModes[0].DispInfo.AcpiId; +} + +void VioGpuVidPN::Powerdown() { + DestroyFrameBufferObj(TRUE); + m_CurrentModes[0].Flags.FrameBufferIsActive = FALSE; + m_CurrentModes[0].FrameBuffer.Ptr = NULL; +} + +NTSTATUS VioGpuVidPN::CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + VIOGPU_ASSERT(pCommitVidPn != NULL); + VIOGPU_ASSERT(pCommitVidPn->AffectedVidPnSourceId < MAX_VIEWS); + + NTSTATUS Status; + SIZE_T NumPaths = 0; + D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0; + D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0; + CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL; + CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL; + CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL; + CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL; + CONST D3DKMDT_VIDPN_SOURCE_MODE* pPinnedVidPnSourceModeInfo = NULL; + + if (pCommitVidPn->Flags.PathPoweredOff) + { + Status = STATUS_SUCCESS; + goto CommitVidPnExit; + } + + Status = m_pDxgkInterface->DxgkCbQueryVidPnInterface(pCommitVidPn->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbQueryVidPnInterface failed with Status = 0x%X, hFunctionalVidPn = 0x%llu\n", + Status, LONG_PTR(pCommitVidPn->hFunctionalVidPn))); + goto CommitVidPnExit; + } + + Status = pVidPnInterface->pfnGetTopology(pCommitVidPn->hFunctionalVidPn, &hVidPnTopology, &pVidPnTopologyInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetTopology failed with Status = 0x%X, hFunctionalVidPn = 0x%llu\n", + Status, LONG_PTR(pCommitVidPn->hFunctionalVidPn))); + goto CommitVidPnExit; + } + + Status = pVidPnTopologyInterface->pfnGetNumPaths(hVidPnTopology, &NumPaths); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetNumPaths failed with Status = 0x%X, hVidPnTopology = 0x%llu\n", Status, LONG_PTR(hVidPnTopology))); + goto CommitVidPnExit; + } + + if (NumPaths != 0) + { + Status = pVidPnInterface->pfnAcquireSourceModeSet(pCommitVidPn->hFunctionalVidPn, + pCommitVidPn->AffectedVidPnSourceId, + &hVidPnSourceModeSet, + &pVidPnSourceModeSetInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireSourceModeSet failed with Status = 0x%X, hFunctionalVidPn = 0x%llu, SourceId = 0x%I64x\n", + Status, LONG_PTR(pCommitVidPn->hFunctionalVidPn), pCommitVidPn->AffectedVidPnSourceId)); + goto CommitVidPnExit; + } + + Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pPinnedVidPnSourceModeInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePinnedModeInfo failed with Status = 0x%X, hFunctionalVidPn = 0x%llu\n", + Status, LONG_PTR(pCommitVidPn->hFunctionalVidPn))); + goto CommitVidPnExit; + } + } + else + { + DbgPrint(TRACE_LEVEL_ERROR, ("%s no vidpn paths found", __FUNCTION__)); + pPinnedVidPnSourceModeInfo = NULL; + } + + if (pPinnedVidPnSourceModeInfo == NULL) + { + Status = STATUS_SUCCESS; + goto CommitVidPnExit; + } + + Status = IsVidPnSourceModeFieldsValid(pPinnedVidPnSourceModeInfo); + if (!NT_SUCCESS(Status)) + { + goto CommitVidPnExit; + } + + SIZE_T NumPathsFromSource = 0; + Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, &NumPathsFromSource); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetNumPathsFromSource failed with Status = 0x%X, hVidPnTopology = 0x%llu\n", Status, LONG_PTR(hVidPnTopology))); + goto CommitVidPnExit; + } + + for (SIZE_T PathIndex = 0; PathIndex < NumPathsFromSource; ++PathIndex) + { + D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId = D3DDDI_ID_UNINITIALIZED; + Status = pVidPnTopologyInterface->pfnEnumPathTargetsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex, &TargetId); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnEnumPathTargetsFromSource failed with Status = 0x%X, hVidPnTopology = 0x%llu, SourceId = 0x%I64x, PathIndex = 0x%I64x\n", + Status, LONG_PTR(hVidPnTopology), pCommitVidPn->AffectedVidPnSourceId, PathIndex)); + goto CommitVidPnExit; + } + + Status = pVidPnTopologyInterface->pfnAcquirePathInfo(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId, &pVidPnPresentPath); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePathInfo failed with Status = 0x%X, hVidPnTopology = 0x%llu, SourceId = 0x%I64x, TargetId = 0x%I64x\n", + Status, LONG_PTR(hVidPnTopology), pCommitVidPn->AffectedVidPnSourceId, TargetId)); + goto CommitVidPnExit; + } + + Status = IsVidPnPathFieldsValid(pVidPnPresentPath); + if (!NT_SUCCESS(Status)) + { + goto CommitVidPnExit; + } + + Status = SetSourceModeAndPath(pPinnedVidPnSourceModeInfo, pVidPnPresentPath); + if (!NT_SUCCESS(Status)) + { + goto CommitVidPnExit; + } + + Status = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleasePathInfo failed with Status = 0x%X, hVidPnTopoogy = 0x%llu, pVidPnPresentPath = %p\n", + Status, LONG_PTR(hVidPnTopology), pVidPnPresentPath)); + goto CommitVidPnExit; + } + pVidPnPresentPath = NULL; + } + +CommitVidPnExit: + + NTSTATUS TempStatus = STATUS_SUCCESS; + + if ((pVidPnSourceModeSetInterface != NULL) && + (hVidPnSourceModeSet != 0) && + (pPinnedVidPnSourceModeInfo != NULL)) + { + TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pPinnedVidPnSourceModeInfo); + NT_ASSERT(NT_SUCCESS(TempStatus)); + } + + if ((pVidPnInterface != NULL) && + (pCommitVidPn->hFunctionalVidPn != 0) && + (hVidPnSourceModeSet != 0)) + { + TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pCommitVidPn->hFunctionalVidPn, hVidPnSourceModeSet); + NT_ASSERT(NT_SUCCESS(TempStatus)); + } + + if ((pVidPnTopologyInterface != NULL) && + (hVidPnTopology != 0) && + (pVidPnPresentPath != NULL)) + { + TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); + NT_ASSERT(NT_SUCCESS(TempStatus)); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + return Status; +} + +NTSTATUS VioGpuVidPN::SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode, + CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + + CURRENT_MODE* pCurrentMode = &m_CurrentModes[pPath->VidPnSourceId]; + DbgPrint(TRACE_LEVEL_FATAL, ("---> %s (%dx%d)\n", __FUNCTION__, + pSourceMode->Format.Graphics.VisibleRegionSize.cx, pSourceMode->Format.Graphics.VisibleRegionSize.cy)); + pCurrentMode->Scaling = pPath->ContentTransformation.Scaling; + pCurrentMode->SrcModeWidth = pSourceMode->Format.Graphics.VisibleRegionSize.cx; + pCurrentMode->SrcModeHeight = pSourceMode->Format.Graphics.VisibleRegionSize.cy; + pCurrentMode->Rotation = pPath->ContentTransformation.Rotation; + + pCurrentMode->DispInfo.Width = pSourceMode->Format.Graphics.PrimSurfSize.cx; + pCurrentMode->DispInfo.Height = pSourceMode->Format.Graphics.PrimSurfSize.cy; + pCurrentMode->DispInfo.Pitch = pSourceMode->Format.Graphics.PrimSurfSize.cx * BPPFromPixelFormat(pCurrentMode->DispInfo.ColorFormat) / BITS_PER_BYTE; + + if (NT_SUCCESS(Status)) + { + pCurrentMode->Flags.FullscreenPresent = TRUE; + for (USHORT ModeIndex = 0; ModeIndex < GetModeCount(); ++ModeIndex) + { + PVIDEO_MODE_INFORMATION pModeInfo = &m_ModeInfo[ModeIndex]; + if (pCurrentMode->DispInfo.Width == pModeInfo->VisScreenWidth && + pCurrentMode->DispInfo.Height == pModeInfo->VisScreenHeight) + { + Status = SetCurrentMode(m_ModeNumbers[ModeIndex], pCurrentMode); + if (NT_SUCCESS(Status)) + { + m_CurrentMode = ModeIndex; + } + break; + } + } + } + + return Status; +} + +NTSTATUS VioGpuVidPN::IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + if (pPath->VidPnSourceId >= MAX_VIEWS) + { + DbgPrint(TRACE_LEVEL_ERROR, ("VidPnSourceId is 0x%I64x is too high (MAX_VIEWS is 0x%I64x)", + pPath->VidPnSourceId, MAX_VIEWS)); + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE; + } + else if (pPath->VidPnTargetId >= MAX_CHILDREN) + { + DbgPrint(TRACE_LEVEL_ERROR, ("VidPnTargetId is 0x%I64x is too high (MAX_CHILDREN is 0x%I64x)", + pPath->VidPnTargetId, MAX_CHILDREN)); + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET; + } + else if (pPath->GammaRamp.Type != D3DDDI_GAMMARAMP_DEFAULT) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pPath contains a gamma ramp (0x%I64x)", pPath->GammaRamp.Type)); + return STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED; + } + else if ((pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_IDENTITY) && + (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_CENTERED) && + (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_NOTSPECIFIED) && + (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_UNINITIALIZED)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pPath contains a non-identity scaling (0x%I64x)", pPath->ContentTransformation.Scaling)); + return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED; + } + else if ((pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_IDENTITY) && + (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_ROTATE90) && + (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_NOTSPECIFIED) && + (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_UNINITIALIZED)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pPath contains a not-supported rotation (0x%I64x)", pPath->ContentTransformation.Rotation)); + return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED; + } + else if ((pPath->VidPnTargetColorBasis != D3DKMDT_CB_SCRGB) && + (pPath->VidPnTargetColorBasis != D3DKMDT_CB_UNINITIALIZED)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pPath has a non-linear RGB color basis (0x%I64x)", pPath->VidPnTargetColorBasis)); + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuVidPN::IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + if (pSourceMode->Type != D3DKMDT_RMT_GRAPHICS) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode is a non-graphics mode (0x%I64x)", pSourceMode->Type)); + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; + } + else if ((pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_SCRGB) && + (pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_UNINITIALIZED)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode has a non-linear RGB color basis (0x%I64x)", pSourceMode->Format.Graphics.ColorBasis)); + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; + } + else if (pSourceMode->Format.Graphics.PixelValueAccessMode != D3DKMDT_PVAM_DIRECT) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode has a palettized access mode (0x%I64x)", pSourceMode->Format.Graphics.PixelValueAccessMode)); + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; + } + else + { + if (pSourceMode->Format.Graphics.PixelFormat == D3DDDIFMT_A8R8G8B8) + { + return STATUS_SUCCESS; + } + } + + DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode has an unknown pixel format (0x%I64x)", pSourceMode->Format.Graphics.PixelFormat)); + + return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE; +} + +NTSTATUS VioGpuVidPN::UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + VIOGPU_ASSERT(pUpdateActiveVidPnPresentPath != NULL); + + NTSTATUS Status = IsVidPnPathFieldsValid(&(pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo)); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Flags.FullscreenPresent = TRUE; + + m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Rotation = pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.ContentTransformation.Rotation; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuVidPN::GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo) +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + UINT ModeCount = 0; + delete[] m_ModeInfo; + delete[] m_ModeNumbers; + m_ModeInfo = NULL; + m_ModeNumbers = NULL; + + while ((gpu_disp_modes[ModeCount].XResolution >= MIN_WIDTH_SIZE) && + (gpu_disp_modes[ModeCount].YResolution >= MIN_HEIGHT_SIZE)) ModeCount++; + + ModeCount += 1; + m_ModeInfo = new (PagedPool) VIDEO_MODE_INFORMATION[ModeCount]; + if (!m_ModeInfo) + { + Status = STATUS_NO_MEMORY; + DbgPrint(TRACE_LEVEL_ERROR, ("VioGpuVidPN::GetModeList failed to allocate m_ModeInfo memory\n")); + return Status; + } + RtlZeroMemory(m_ModeInfo, sizeof(VIDEO_MODE_INFORMATION) * ModeCount); + + m_ModeNumbers = new (PagedPool) USHORT[ModeCount]; + if (!m_ModeNumbers) + { + Status = STATUS_NO_MEMORY; + DbgPrint(TRACE_LEVEL_ERROR, ("VioGpuVidPN::GetModeList failed to allocate m_ModeNumbers memory\n")); + return Status; + } + RtlZeroMemory(m_ModeNumbers, sizeof(USHORT) * ModeCount); + + ProcessEdid(); + + m_CurrentMode = 0; + DbgPrint(TRACE_LEVEL_INFORMATION, ("m_ModeInfo = 0x%p, m_ModeNumbers = 0x%p\n", m_ModeInfo, m_ModeNumbers)); + + 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; + + USHORT SuitableModeCount; + USHORT CurrentMode; + + for (CurrentMode = 0, SuitableModeCount = 0; + CurrentMode < ModeCount - 1; + CurrentMode++) + { + + PVIOGPU_DISP_MODE pModeInfo = &gpu_disp_modes[CurrentMode]; + + DbgPrint(TRACE_LEVEL_INFORMATION, ("%s: modes[%d] x_res = %d, y_res = %d\n", + __FUNCTION__, CurrentMode, pModeInfo->XResolution, pModeInfo->YResolution)); + + if (pModeInfo->XResolution >= pDispInfo->Width && + pModeInfo->YResolution >= pDispInfo->Height) + { + m_ModeNumbers[SuitableModeCount] = SuitableModeCount; + SetVideoModeInfo(SuitableModeCount, pModeInfo); + if (pModeInfo->XResolution == NOM_WIDTH_SIZE && + pModeInfo->YResolution == NOM_HEIGHT_SIZE) + { + m_CurrentMode = SuitableModeCount; + } + SuitableModeCount++; + } + } + + if (SuitableModeCount == 0) + { + DbgPrint(TRACE_LEVEL_ERROR, ("No video modes supported\n")); + Status = STATUS_UNSUCCESSFUL; + } + + m_CustomMode = SuitableModeCount; + for (CurrentMode = SuitableModeCount; + CurrentMode < SuitableModeCount + 1; + CurrentMode++) + { + m_ModeNumbers[CurrentMode] = CurrentMode; + memcpy(&m_ModeInfo[CurrentMode], &m_ModeInfo[m_CurrentMode], sizeof(VIDEO_MODE_INFORMATION)); + } + + m_ModeCount = SuitableModeCount + 1; + DbgPrint(TRACE_LEVEL_INFORMATION, ("ModeCount filtered %d\n", m_ModeCount)); + + GetDisplayInfo(); + + for (ULONG idx = 0; idx < ModeCount; idx++) + { + DbgPrint(TRACE_LEVEL_FATAL, ("type %d, XRes = %d, YRes = %d\n", + m_ModeNumbers[idx], + m_ModeInfo[idx].VisScreenWidth, + m_ModeInfo[idx].VisScreenHeight)); + } + + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS VioGpuVidPN::SetCurrentMode(ULONG Mode, CURRENT_MODE* pCurrentMode) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_ERROR, ("---> %s: Mode = %d\n", __FUNCTION__, Mode)); + for (ULONG idx = 0; idx < GetModeCount(); idx++) + { + if (Mode == m_ModeNumbers[idx]) + { + if (pCurrentMode->Flags.FrameBufferIsActive) { + DestroyFrameBufferObj(FALSE); + pCurrentMode->Flags.FrameBufferIsActive = FALSE; + } + CreateFrameBufferObj(&m_ModeInfo[idx], pCurrentMode); + DbgPrint(TRACE_LEVEL_ERROR, ("%s device: setting current mode %d (%d x %d)\n", + __FUNCTION__, Mode, m_ModeInfo[idx].VisScreenWidth, + m_ModeInfo[idx].VisScreenHeight)); + return STATUS_SUCCESS; + } + } + DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s failed\n", __FUNCTION__)); + return STATUS_UNSUCCESSFUL; +} + +void VioGpuVidPN::CreateFrameBufferObj(PVIDEO_MODE_INFORMATION pModeInfo, CURRENT_MODE* pCurrentMode) +{ + UINT resid, format, size; + VioGpuObj* obj; + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s : (%d x %d)\n", __FUNCTION__, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight)); + ASSERT(m_pFrameBuf == NULL); + size = pModeInfo->ScreenStride * pModeInfo->VisScreenHeight; + format = ColorFormat(pCurrentMode->DispInfo.ColorFormat); + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s - (%d -> %d)\n", __FUNCTION__, pCurrentMode->DispInfo.ColorFormat, format)); + resid = m_pAdapter->resourceIdr.GetId(); + m_pAdapter->ctrlQueue.CreateResource(resid, format, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight); + obj = new(NonPagedPoolNx) VioGpuObj(); + if (!obj->Init(size, &m_pAdapter->frameSegment)) + { + DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s Failed to init obj size = %d\n", __FUNCTION__, size)); + delete obj; + return; + } + + GpuObjectAttach(resid, obj); + //long* pvAddr = (long*)m_FrameSegment.GetVirtualAddress(); + //for (int i = 0; i < 0x8000 / 4; i += 1) { + // pvAddr[i] = 0x00ff8800; + //}; + resid = 1; + + m_pFrameBuf = obj; + pCurrentMode->FrameBuffer.Ptr = obj->GetVirtualAddress(); + pCurrentMode->Flags.FrameBufferIsActive = TRUE; + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +void VioGpuVidPN::DestroyFrameBufferObj(BOOLEAN bReset) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + UINT resid = 0; + + if (m_pFrameBuf != NULL) + { + resid = (UINT)m_pFrameBuf->GetId(); + m_pAdapter->ctrlQueue.DetachBacking(resid); + m_pAdapter->ctrlQueue.DestroyResource(resid); + if (bReset == TRUE) { + m_pAdapter->ctrlQueue.SetScanout(0, 0, 0, 0, 0, 0); + } + delete m_pFrameBuf; + m_pFrameBuf = NULL; + m_pAdapter->resourceIdr.PutId(resid); + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +BOOLEAN VioGpuVidPN::GpuObjectAttach(UINT res_id, VioGpuObj* obj) +{ + PAGED_CODE(); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + PGPU_MEM_ENTRY ents = NULL; + PSCATTER_GATHER_LIST sgl = NULL; + UINT size = 0; + sgl = obj->GetSGList(); + size = sizeof(GPU_MEM_ENTRY) * sgl->NumberOfElements; + ents = reinterpret_cast (new (NonPagedPoolNx) BYTE[size]); + + if (!ents) + { + DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s cannot allocate memory %x bytes numberofentries = %d\n", __FUNCTION__, size, sgl->NumberOfElements)); + return FALSE; + } + //FIXME + RtlZeroMemory(ents, size); + + for (UINT i = 0; i < sgl->NumberOfElements; i++) + { + ents[i].addr = sgl->Elements[i].Address.QuadPart; + ents[i].length = sgl->Elements[i].Length; + ents[i].padding = 0; + } + + m_pAdapter->ctrlQueue.AttachBacking(res_id, ents, sgl->NumberOfElements); + obj->SetId(res_id); + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return TRUE; +} + +NTSTATUS VioGpuVidPN::EscapeCustomResoulution(VIOGPU_DISP_MODE *resolution) { + PAGED_CODE(); + + resolution->XResolution = (USHORT)m_ModeInfo[m_CustomMode].VisScreenWidth; + resolution->YResolution = (USHORT)m_ModeInfo[m_CustomMode].VisScreenHeight; + + return STATUS_SUCCESS; +} + + + +NTSTATUS VioGpuVidPN::QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + VIOGPU_ASSERT(pVidPnHWCaps != NULL); + VIOGPU_ASSERT(pVidPnHWCaps->SourceId < MAX_VIEWS); + VIOGPU_ASSERT(pVidPnHWCaps->TargetId < MAX_CHILDREN); + + pVidPnHWCaps->VidPnHWCaps.DriverRotation = 1; + pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0; + pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0; + pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 1; + pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0; + pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0; + pVidPnHWCaps->VidPnHWCaps.Reserved = 0; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuVidPN::IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + VIOGPU_ASSERT(pIsSupportedVidPn != NULL); + + if (pIsSupportedVidPn->hDesiredVidPn == 0) + { + pIsSupportedVidPn->IsVidPnSupported = TRUE; + return STATUS_SUCCESS; + } + + pIsSupportedVidPn->IsVidPnSupported = FALSE; + //DbgPrint(TRACE_LEVEL_ERROR, ("vidpn %d\n", pIsSupportedVidPn->hDesiredVidPn)); + CONST DXGK_VIDPN_INTERFACE* pVidPnInterface; + NTSTATUS Status = m_pDxgkInterface->DxgkCbQueryVidPnInterface(pIsSupportedVidPn->hDesiredVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbQueryVidPnInterface failed with Status = 0x%X, hDesiredVidPn = %llu\n", + Status, LONG_PTR(pIsSupportedVidPn->hDesiredVidPn))); + return Status; + } + + D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology; + CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface; + Status = pVidPnInterface->pfnGetTopology(pIsSupportedVidPn->hDesiredVidPn, &hVidPnTopology, &pVidPnTopologyInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetTopology failed with Status = 0x%X, hDesiredVidPn = %llu\n", + Status, LONG_PTR(pIsSupportedVidPn->hDesiredVidPn))); + return Status; + } + + for (D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = 0; SourceId < MAX_VIEWS; ++SourceId) + { + SIZE_T NumPathsFromSource = 0; + Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, SourceId, &NumPathsFromSource); + if (Status == STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY) + { + continue; + } + else if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetNumPathsFromSource failed with Status = 0x%X hVidPnTopology = %llu, SourceId = %llu", + Status, LONG_PTR(hVidPnTopology), LONG_PTR(SourceId))); + return Status; + } + else if (NumPathsFromSource > MAX_CHILDREN) + { + return STATUS_SUCCESS; + } + } + + pIsSupportedVidPn->IsVidPnSupported = TRUE; + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +NTSTATUS VioGpuVidPN::RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VIOGPU_ASSERT(pRecommendFunctionalVidPn == NULL); + + return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN; +} + +NTSTATUS VioGpuVidPN::RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__)); + + VIOGPU_ASSERT(pRecommendVidPnTopology == NULL); + + return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN; +} + +NTSTATUS VioGpuVidPN::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + return AddSingleMonitorMode(pRecommendMonitorModes); +} + + +NTSTATUS VioGpuVidPN::AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface, + D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet, + D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + UNREFERENCED_PARAMETER(SourceId); + + for (ULONG idx = 0; idx < GetModeCount(); ++idx) + { + D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL; + PVIDEO_MODE_INFORMATION pModeInfo = &m_ModeInfo[idx]; + NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%X, hVidPnSourceModeSet = %llu", + Status, LONG_PTR(hVidPnSourceModeSet))); + return Status; + } + + pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS; + pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = pModeInfo->VisScreenWidth; + pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = pModeInfo->VisScreenHeight; + pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize; + pVidPnSourceModeInfo->Format.Graphics.Stride = pModeInfo->ScreenStride; + pVidPnSourceModeInfo->Format.Graphics.PixelFormat = D3DDDIFMT_A8R8G8B8; + pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB; + pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT; + + Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo); + if (!NT_SUCCESS(Status)) + { + NTSTATUS TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo); + UNREFERENCED_PARAMETER(TempStatus); + NT_ASSERT(NT_SUCCESS(TempStatus)); + + if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%X, hVidPnSourceModeSet = %llu, pVidPnSourceModeInfo = %p", + Status, LONG_PTR(hVidPnSourceModeSet), pVidPnSourceModeInfo)); + return Status; + } + } + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + +VOID VioGpuVidPN::BuildVideoSignalInfo(D3DKMDT_VIDEO_SIGNAL_INFO* pVideoSignalInfo, PVIDEO_MODE_INFORMATION pModeInfo) +{ + PAGED_CODE(); + + pVideoSignalInfo->VideoStandard = D3DKMDT_VSS_OTHER; + pVideoSignalInfo->TotalSize.cx = pModeInfo->VisScreenWidth; + pVideoSignalInfo->TotalSize.cy = pModeInfo->VisScreenHeight; + +#if 1 + pVideoSignalInfo->VSyncFreq.Numerator = 148500000; + pVideoSignalInfo->VSyncFreq.Denominator = 2475000; + pVideoSignalInfo->HSyncFreq.Numerator = 67500; + pVideoSignalInfo->HSyncFreq.Denominator = 1; + pVideoSignalInfo->PixelRate = 148500000; +#else + + pVideoSignalInfo->VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; + pVideoSignalInfo->VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; + pVideoSignalInfo->HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED; + pVideoSignalInfo->HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED; + pVideoSignalInfo->PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED; +#endif + pVideoSignalInfo->ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE; +} + +NTSTATUS VioGpuVidPN::AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface, + D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet, + _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo, + D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + UNREFERENCED_PARAMETER(pVidPnPinnedSourceModeInfo); + + D3DKMDT_VIDPN_TARGET_MODE* pVidPnTargetModeInfo = NULL; + NTSTATUS Status = STATUS_SUCCESS; + + for (UINT ModeIndex = 0; ModeIndex < GetModeCount(); ++ModeIndex) + { + PVIDEO_MODE_INFORMATION pModeInfo = &m_ModeInfo[SourceId]; + pVidPnTargetModeInfo = NULL; + Status = pVidPnTargetModeSetInterface->pfnCreateNewModeInfo(hVidPnTargetModeSet, &pVidPnTargetModeInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%X, hVidPnTargetModeSet = %llu", + Status, LONG_PTR(hVidPnTargetModeSet))); + return Status; + } + pVidPnTargetModeInfo->VideoSignalInfo.ActiveSize = pVidPnTargetModeInfo->VideoSignalInfo.TotalSize; + BuildVideoSignalInfo(&pVidPnTargetModeInfo->VideoSignalInfo, pModeInfo); + + pVidPnTargetModeInfo->Preference = D3DKMDT_MP_NOTPREFERRED; // TODO: another logic for prefferred mode. Maybe the pinned source mode + + Status = pVidPnTargetModeSetInterface->pfnAddMode(hVidPnTargetModeSet, pVidPnTargetModeInfo); + if (!NT_SUCCESS(Status)) + { + if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%X, hVidPnTargetModeSet = 0x%llu, pVidPnTargetModeInfo = %p\n", + Status, LONG_PTR(hVidPnTargetModeSet), pVidPnTargetModeInfo)); + } + + Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnTargetModeInfo); + NT_ASSERT(NT_SUCCESS(Status)); + } + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return STATUS_SUCCESS; +} + + +NTSTATUS VioGpuVidPN::AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes) +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + D3DKMDT_MONITOR_SOURCE_MODE* pMonitorSourceMode = NULL; + PVIDEO_MODE_INFORMATION pVbeModeInfo = NULL; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%X, hMonitorSourceModeSet = 0x%llu\n", + Status, LONG_PTR(pRecommendMonitorModes->hMonitorSourceModeSet))); + return Status; + } + + pVbeModeInfo = &m_ModeInfo[m_CurrentMode]; + + BuildVideoSignalInfo(&pMonitorSourceMode->VideoSignalInfo, pVbeModeInfo); + + pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER; + pMonitorSourceMode->Preference = D3DKMDT_MP_PREFERRED; + pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB; + pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8; + pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8; + pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8; + pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8; + + Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); + if (!NT_SUCCESS(Status)) + { + if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%X, hMonitorSourceModeSet = 0x%llu, pMonitorSourceMode = 0x%p\n", + Status, LONG_PTR(pRecommendMonitorModes->hMonitorSourceModeSet), pMonitorSourceMode)); + } + else + { + Status = STATUS_SUCCESS; + } + + NTSTATUS TempStatus = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); + UNREFERENCED_PARAMETER(TempStatus); + NT_ASSERT(NT_SUCCESS(TempStatus)); + return Status; + } + + for (UINT Idx = 0; Idx < GetModeCount(); ++Idx) + { + pVbeModeInfo = &m_ModeInfo[Idx]; + + Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%X, hMonitorSourceModeSet = 0x%llu\n", + Status, LONG_PTR(pRecommendMonitorModes->hMonitorSourceModeSet))); + return Status; + } + + DbgPrint(TRACE_LEVEL_INFORMATION, ("%s: add pref mode, dimensions %ux%u, taken from DxgkCbAcquirePostDisplayOwnership at StartDevice\n", + __FUNCTION__, pVbeModeInfo->VisScreenWidth, pVbeModeInfo->VisScreenHeight)); + + BuildVideoSignalInfo(&pMonitorSourceMode->VideoSignalInfo, pVbeModeInfo); + + pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER; + pMonitorSourceMode->Preference = D3DKMDT_MP_NOTPREFERRED; + pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB; + pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8; + pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8; + pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8; + pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8; + + Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); + if (!NT_SUCCESS(Status)) + { + if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%X, hMonitorSourceModeSet = 0x%llu, pMonitorSourceMode = 0x%p\n", + Status, LONG_PTR(pRecommendMonitorModes->hMonitorSourceModeSet), pMonitorSourceMode)); + } + + Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode); + NT_ASSERT(NT_SUCCESS(Status)); + } + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS VioGpuVidPN::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality) +{ + PAGED_CODE(); + + //DbgBreakPoint(); + + VIOGPU_ASSERT(pEnumCofuncModality != NULL); + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0; + D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0; + D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet = 0; + CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL; + CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL; + CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL; + CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface = NULL; + CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL; + CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPathTemp = NULL; + CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo = NULL; + CONST D3DKMDT_VIDPN_TARGET_MODE* pVidPnPinnedTargetModeInfo = NULL; + + NTSTATUS Status = m_pDxgkInterface->DxgkCbQueryVidPnInterface(pEnumCofuncModality->hConstrainingVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbQueryVidPnInterface failed with Status = 0x%X, hFunctionalVidPn = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn))); + return Status; + } + + Status = pVidPnInterface->pfnGetTopology(pEnumCofuncModality->hConstrainingVidPn, &hVidPnTopology, &pVidPnTopologyInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetTopology failed with Status = 0x%X, hFunctionalVidPn = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn))); + return Status; + } + + Status = pVidPnTopologyInterface->pfnAcquireFirstPathInfo(hVidPnTopology, &pVidPnPresentPath); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireFirstPathInfo failed with Status = 0x%X, hVidPnTopology = 0x%llu\n", + Status, LONG_PTR(hVidPnTopology))); + return Status; + } + + while (Status != STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET) + { + Status = pVidPnInterface->pfnAcquireSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, + pVidPnPresentPath->VidPnSourceId, + &hVidPnSourceModeSet, + &pVidPnSourceModeSetInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, SourceId = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(pVidPnPresentPath->VidPnSourceId))); + break; + } + + Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pVidPnPinnedSourceModeInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePinnedModeInfo failed with Status = 0x%X, hVidPnSourceModeSet = 0x%llu\n", + Status, LONG_PTR(hVidPnSourceModeSet))); + break; + } + + if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNSOURCE) && + (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId))) + { + if (pVidPnPinnedSourceModeInfo == NULL) + { + Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, hVidPnSourceModeSet = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(hVidPnSourceModeSet))); + break; + } + hVidPnSourceModeSet = 0; + + Status = pVidPnInterface->pfnCreateNewSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, + pVidPnPresentPath->VidPnSourceId, + &hVidPnSourceModeSet, + &pVidPnSourceModeSetInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, SourceId = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(pVidPnPresentPath->VidPnSourceId))); + break; + } + + { + Status = AddSingleSourceMode(pVidPnSourceModeSetInterface, hVidPnSourceModeSet, pVidPnPresentPath->VidPnSourceId); + } + + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("AddSingleSourceMode failed with Status = 0x%X, hFunctionalVidPn = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn))); + break; + } + + Status = pVidPnInterface->pfnAssignSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAssignSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, SourceId = 0x%llu, hVidPnSourceModeSet = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(pVidPnPresentPath->VidPnSourceId), LONG_PTR(hVidPnSourceModeSet))); + break; + } + hVidPnSourceModeSet = 0; + } + } + + if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNTARGET) && + (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId))) + { + Status = pVidPnInterface->pfnAcquireTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, + pVidPnPresentPath->VidPnTargetId, + &hVidPnTargetModeSet, + &pVidPnTargetModeSetInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, TargetId = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(pVidPnPresentPath->VidPnTargetId))); + break; + } + + Status = pVidPnTargetModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnTargetModeSet, &pVidPnPinnedTargetModeInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePinnedModeInfo failed with Status = 0x%X, hVidPnTargetModeSet = 0x%llu\n", + Status, LONG_PTR(hVidPnTargetModeSet))); + break; + } + + if (pVidPnPinnedTargetModeInfo == NULL) + { + Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, hVidPnTargetModeSet = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(hVidPnTargetModeSet))); + break; + } + hVidPnTargetModeSet = 0; + + Status = pVidPnInterface->pfnCreateNewTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, + pVidPnPresentPath->VidPnTargetId, + &hVidPnTargetModeSet, + &pVidPnTargetModeSetInterface); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, TargetId = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(pVidPnPresentPath->VidPnTargetId))); + break; + } + + Status = AddSingleTargetMode(pVidPnTargetModeSetInterface, hVidPnTargetModeSet, pVidPnPinnedSourceModeInfo, pVidPnPresentPath->VidPnSourceId); + + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("AddSingleTargetMode failed with Status = 0x%X, hFunctionalVidPn = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn))); + break; + } + + Status = pVidPnInterface->pfnAssignTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAssignTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, TargetId = 0x%llu, hVidPnTargetModeSet = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(pVidPnPresentPath->VidPnTargetId), LONG_PTR(hVidPnTargetModeSet))); + break; + } + hVidPnTargetModeSet = 0; + } + else + { + Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseModeInfo failed with Status = 0x%X, hVidPnTargetModeSet = 0x%llu, pVidPnPinnedTargetModeInfo = %p\n", + Status, LONG_PTR(hVidPnTargetModeSet), pVidPnPinnedTargetModeInfo)); + break; + } + pVidPnPinnedTargetModeInfo = NULL; + + Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, hVidPnTargetModeSet = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(hVidPnTargetModeSet))); + break; + } + hVidPnTargetModeSet = 0; + } + } + + if (pVidPnPinnedSourceModeInfo != NULL) + { + Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseModeInfo failed with Status = 0x%X, hVidPnSourceModeSet = 0x%llu, pVidPnPinnedSourceModeInfo = %p\n", + Status, LONG_PTR(hVidPnSourceModeSet), pVidPnPinnedSourceModeInfo)); + break; + } + pVidPnPinnedSourceModeInfo = NULL; + } + + if (hVidPnSourceModeSet != 0) + { + Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%llu, hVidPnSourceModeSet = 0x%llu\n", + Status, LONG_PTR(pEnumCofuncModality->hConstrainingVidPn), LONG_PTR(hVidPnSourceModeSet))); + break; + } + hVidPnSourceModeSet = 0; + } + + D3DKMDT_VIDPN_PRESENT_PATH LocalVidPnPresentPath = *pVidPnPresentPath; + BOOLEAN SupportFieldsModified = FALSE; + + if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_SCALING) && + (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) && + (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId))) + { + if (pVidPnPresentPath->ContentTransformation.Scaling == D3DKMDT_VPPS_UNPINNED) + { + RtlZeroMemory(&(LocalVidPnPresentPath.ContentTransformation.ScalingSupport), sizeof(D3DKMDT_VIDPN_PRESENT_PATH_SCALING_SUPPORT)); + LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Identity = 1; + LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Centered = 1; + SupportFieldsModified = TRUE; + } + } + + if (!((pEnumCofuncModality->EnumPivotType != D3DKMDT_EPT_ROTATION) && + (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) && + (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId))) + { + if (pVidPnPresentPath->ContentTransformation.Rotation == D3DKMDT_VPPR_UNPINNED) + { + LocalVidPnPresentPath.ContentTransformation.RotationSupport.Identity = 1; + LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate90 = 1; + LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate180 = 0; + LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate270 = 0; + SupportFieldsModified = TRUE; + } + } + + if (SupportFieldsModified) + { + Status = pVidPnTopologyInterface->pfnUpdatePathSupportInfo(hVidPnTopology, &LocalVidPnPresentPath); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnUpdatePathSupportInfo failed with Status = 0x%X, hVidPnTopology = 0x%llu\n", + Status, LONG_PTR(hVidPnTopology))); + break; + } + } + + pVidPnPresentPathTemp = pVidPnPresentPath; + Status = pVidPnTopologyInterface->pfnAcquireNextPathInfo(hVidPnTopology, pVidPnPresentPathTemp, &pVidPnPresentPath); + if (!NT_SUCCESS(Status)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireNextPathInfo failed with Status = 0x%X, hVidPnTopology = 0x%llu, pVidPnPresentPathTemp = %p\n", + Status, LONG_PTR(hVidPnTopology), pVidPnPresentPathTemp)); + break; + } + + NTSTATUS TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp); + if (!NT_SUCCESS(TempStatus)) + { + DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleasePathInfo failed with Status = 0x%X, hVidPnTopology = 0x%llu, pVidPnPresentPathTemp = %p\n", + TempStatus, LONG_PTR(hVidPnTopology), pVidPnPresentPathTemp)); + Status = TempStatus; + break; + } + pVidPnPresentPathTemp = NULL; + } + + if (Status == STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET) + { + Status = STATUS_SUCCESS; + } + + NTSTATUS TempStatus = STATUS_NOT_FOUND; + + if ((pVidPnSourceModeSetInterface != NULL) && + (pVidPnPinnedSourceModeInfo != NULL)) + { + TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo); + VIOGPU_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if ((pVidPnTargetModeSetInterface != NULL) && + (pVidPnPinnedTargetModeInfo != NULL)) + { + TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo); + VIOGPU_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if (pVidPnPresentPath != NULL) + { + TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath); + VIOGPU_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if (pVidPnPresentPathTemp != NULL) + { + TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp); + VIOGPU_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if (hVidPnSourceModeSet != 0) + { + TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet); + VIOGPU_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + if (hVidPnTargetModeSet != 0) + { + TempStatus = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet); + VIOGPU_ASSERT_CHK(NT_SUCCESS(TempStatus)); + } + + VIOGPU_ASSERT_CHK(TempStatus == STATUS_NOT_FOUND || Status != STATUS_SUCCESS); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return Status; +} + +NTSTATUS VioGpuVidPN::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + VIOGPU_ASSERT(pSetVidPnSourceVisibility != NULL); + VIOGPU_ASSERT((pSetVidPnSourceVisibility->VidPnSourceId < MAX_VIEWS) || + (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL)); + + UINT StartVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? 0 : pSetVidPnSourceVisibility->VidPnSourceId; + UINT MaxVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? MAX_VIEWS : pSetVidPnSourceVisibility->VidPnSourceId + 1; + + for (UINT SourceId = StartVidPnSourceId; SourceId < MaxVidPnSourceId; ++SourceId) + { + if (pSetVidPnSourceVisibility->Visible) + { + m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE; + } + else + { + BlackOutScreen(&m_CurrentModes[SourceId]); + } + + m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + + return STATUS_SUCCESS; +} + +VOID VioGpuVidPN::BlackOutScreen(CURRENT_MODE* pCurrentMod) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__)); + + if (pCurrentMod->Flags.FrameBufferIsActive) { + UINT ScreenHeight = pCurrentMod->DispInfo.Height; + UINT ScreenPitch = pCurrentMod->DispInfo.Pitch; + BYTE* pDst = (BYTE*)pCurrentMod->FrameBuffer.Ptr; + + UINT resid = 0; + + if (pDst) + { + RtlZeroMemory(pDst, (ULONGLONG)ScreenHeight * ScreenPitch); + } + + //FIXME!!! rotation + + resid = m_pFrameBuf->GetId(); + + //ctrlQueue.TransferToHost2D(resid, 0UL, pCurrentMod->DispInfo.Width, pCurrentMod->DispInfo.Height, 0, 0); + m_pAdapter->ctrlQueue.ResFlush(resid, pCurrentMod->DispInfo.Width, pCurrentMod->DispInfo.Height, 0, 0); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + +static UCHAR g_gpu_edid[EDID_V1_BLOCK_SIZE] = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ,0xFF, 0x00, // Header + 0x49, 0x14, // Manufacturef Id + 0x34, 0x12, // Manufacturef product code + 0x00, 0x00, 0x00, 0x00, // serial number + 0xff, 0x1d, // year of manufacture + 0x01, // EDID version + 0x04, // EDID revision + 0xa3, // VideoInputDefinition digital, 8-bit, HDMI + 0x00, //MaximumHorizontalImageSize + 0x00, //MaximumVerticallImageSize + 0x78, //DisplayTransferCharacteristics + 0x22, //FeatureSupport + 0xEE, 0x95, 0xA3, 0x54, 0x4C, //ColorCharacteristics + 0x99, 0x26, 0x0F, 0x50, 0x54, + 0x00, 0x00, //EstablishedTimings + 0x00, //ManufacturerTimings + 0x01, 0x01, //StandardTimings[8] + 0x01, 0x01, + 0x01, 0x01, + 0x01, 0x01, + 0x01, 0x01, + 0x01, 0x01, + 0x01, 0x01, + 0x01, 0x01, + 0x6c, 0x20, 0x80, 0x30, 0x42, 0x00, // Descriptor 1 + 0x32, 0x30, 0x40, 0xc0, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0xFD, 0x00, 0x32, // Descriptor 2 + 0x7d, 0x1e, 0xa0, 0x78, 0x01, 0x0a, + 0x20, 0x20 ,0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, // Descriptor 3 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, // Descriptor 4 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // Number of Extentions + 0x00 // CheckSum +}; + +PBYTE VioGpuVidPN::GetEdidData(UINT Id) +{ + PAGED_CODE(); + + return m_bEDID ? m_EDIDs[Id] : (PBYTE)(g_gpu_edid); +} + + +BOOLEAN VioGpuVidPN::GetDisplayInfo(void) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_VBUFFER vbuf = NULL; + ULONG xres = 0; + ULONG yres = 0; + + for (UINT32 i = 0; i < m_pAdapter->m_u32NumScanouts; i++) { + if (m_pAdapter->ctrlQueue.AskDisplayInfo(&vbuf)) { + m_pAdapter->ctrlQueue.GetDisplayInfo(vbuf, i, &xres, &yres); + m_pAdapter->ctrlQueue.ReleaseBuffer(vbuf); + if (xres && yres) { + DbgPrint(TRACE_LEVEL_FATAL, ("---> %s (%dx%d)\n", __FUNCTION__, xres, yres)); + SetCustomDisplay((USHORT)xres, (USHORT)yres); + } + } + } + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return TRUE; +} + +void VioGpuVidPN::ProcessEdid(void) +{ + PAGED_CODE(); + + if (virtio_is_feature_enabled(m_pAdapter->m_u64HostFeatures, VIRTIO_GPU_F_EDID)) { + GetEdids(); + } + FixEdid(); + AddEdidModes(); +} + +void VioGpuVidPN::FixEdid(void) +{ + PAGED_CODE(); + + UCHAR Sum = 0; + PUCHAR buf = GetEdidData(0);; + PEDID_DATA_V1 pdata = (PEDID_DATA_V1)buf; + pdata->MaximumHorizontalImageSize[0] = 0; + pdata->MaximumVerticallImageSize[0] = 0; + pdata->ExtensionFlag[0] = 0; + pdata->Checksum[0] = 0; + for (ULONG i = 0; i < EDID_V1_BLOCK_SIZE; i++) { + Sum += buf[i]; + } + pdata->Checksum[0] = -Sum; +} + +BOOLEAN VioGpuVidPN::GetEdids(void) +{ + PAGED_CODE(); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + + PGPU_VBUFFER vbuf = NULL; + + for (UINT32 i = 0; i < m_pAdapter->m_u32NumScanouts; i++) { + if (m_pAdapter->ctrlQueue.AskEdidInfo(&vbuf, i) && + m_pAdapter->ctrlQueue.GetEdidInfo(vbuf, i, m_EDIDs[i])) { + m_bEDID = TRUE; + } + m_pAdapter->ctrlQueue.ReleaseBuffer(vbuf); + } + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); + return TRUE; +} + +void VioGpuVidPN::AddEdidModes(void) +{ + PAGED_CODE(); + ESTABLISHED_TIMINGS est_timing = ((PEDID_DATA_V1)(GetEdidData(0)))->EstablishedTimings; + MANUFACTURER_TIMINGS manufact_timing = ((PEDID_DATA_V1)(GetEdidData(0)))->ManufacturerTimings; + int modecount = 0; + while (gpu_disp_modes[modecount].XResolution != 0 && gpu_disp_modes[modecount].XResolution != 0) modecount++; + //VioGpuDbgBreak(); +#if NTDDI_VERSION > NTDDI_WINBLUE + if (est_timing.Timing_720x400_88 || est_timing.Timing_720x400_70) { + gpu_disp_modes[modecount].XResolution = 720; gpu_disp_modes[modecount].YResolution = 400; + modecount++; + } +#endif + if (est_timing.Timing_832x624_75) { + gpu_disp_modes[modecount].XResolution = 832; gpu_disp_modes[modecount].YResolution = 624; + modecount++; + } + if (est_timing.Timing_1280x1024_75) { + gpu_disp_modes[modecount].XResolution = 1280; gpu_disp_modes[modecount].YResolution = 1024; + modecount++; + } + if (manufact_timing.Timing_1152x870_75) { + gpu_disp_modes[modecount].XResolution = 1152; gpu_disp_modes[modecount].YResolution = 870; + modecount++; + } + gpu_disp_modes[modecount].XResolution = 0; gpu_disp_modes[modecount].YResolution = 0; + + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); +} + + +void VioGpuVidPN::SetVideoModeInfo(UINT Idx, PVIOGPU_DISP_MODE pModeInfo) +{ + PAGED_CODE(); + + PVIDEO_MODE_INFORMATION pMode = NULL; + + pMode = &m_ModeInfo[Idx]; + pMode->Length = sizeof(VIDEO_MODE_INFORMATION); + pMode->ModeIndex = Idx; + pMode->VisScreenWidth = pModeInfo->XResolution; + pMode->VisScreenHeight = pModeInfo->YResolution; + pMode->ScreenStride = (pModeInfo->XResolution * 4 + 3) & ~0x3; +} + +void VioGpuVidPN::SetCustomDisplay(_In_ USHORT xres, _In_ USHORT yres) +{ + PAGED_CODE(); + + VIOGPU_DISP_MODE tmpModeInfo = { 0 }; + + if (xres < MIN_WIDTH_SIZE || yres < MIN_HEIGHT_SIZE) { + DbgPrint(TRACE_LEVEL_WARNING, ("%s: (%dx%d) less than (%dx%d)\n", __FUNCTION__, + xres, yres, MIN_WIDTH_SIZE, MIN_HEIGHT_SIZE)); + } + tmpModeInfo.XResolution = m_pAdapter->IsFlexResolution() ? xres : max(MIN_WIDTH_SIZE, xres); + tmpModeInfo.YResolution = m_pAdapter->IsFlexResolution() ? yres : max(MIN_HEIGHT_SIZE, yres); + + m_CustomMode = (USHORT)(m_ModeCount - 1); + + DbgPrint(TRACE_LEVEL_FATAL, ("%s - %d (%dx%d)\n", __FUNCTION__, m_CustomMode, tmpModeInfo.XResolution, tmpModeInfo.YResolution)); + + SetVideoModeInfo(m_CustomMode, &tmpModeInfo); +} + +void VioGpuVidPN::Flip() { + PAGED_CODE(); + + if (InterlockedExchange(&m_shouldFlip, 0)) { + if (m_sourceAddress.QuadPart != 0 && m_sourceRes != NULL) { + m_sourceRes->FlushToScreen(0); + } + else { + m_pAdapter->ctrlQueue.SetScanout(0, 0, 0, 0, 0, 0); + } + } + DXGKARGCB_NOTIFY_INTERRUPT_DATA interrupt; + interrupt.InterruptType = DXGK_INTERRUPT_CRTC_VSYNC; + + interrupt.CrtcVsync.VidPnTargetId = 0; + interrupt.CrtcVsync.PhysicalAddress = m_sourceAddress; + + m_pAdapter->NotifyInterrupt(&interrupt, true); +} + +void VioGpuVidPN::FlipThread(void* ctx) { + PAGED_CODE(); + + VioGpuVidPN* vidpn = reinterpret_cast(ctx); + LARGE_INTEGER interval; + interval.QuadPart = 166666LL; + while (true) { + KeDelayExecutionThread(KernelMode, false, &interval); + if (vidpn->m_shouldFlipStop) return; + vidpn->Flip(); + } +} + +PAGED_CODE_SEG_END + + +// +// Non-Paged Code +// +#pragma code_seg(push) +#pragma code_seg() + + +NTSTATUS VioGpuVidPN::SetVidPnSourceAddress(const DXGKARG_SETVIDPNSOURCEADDRESS* pSetVidPnSourceAddress) { + m_sourceAddress = pSetVidPnSourceAddress->PrimaryAddress; + m_sourceRes = reinterpret_cast(pSetVidPnSourceAddress->hAllocation); + InterlockedOr(&m_shouldFlip, 1); + + return STATUS_SUCCESS; +}; + +D3DDDI_VIDEO_PRESENT_SOURCE_ID VioGpuVidPN::FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero) +{ + UNREFERENCED_PARAMETER(TargetId); + for (UINT SourceId = 0; SourceId < MAX_VIEWS; ++SourceId) + { + if (m_CurrentModes[SourceId].FrameBuffer.Ptr != NULL) + { + return SourceId; + } + } + + return DefaultToZero ? 0 : D3DDDI_ID_UNINITIALIZED; +} + +NTSTATUS VioGpuVidPN::SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, + _Out_ UINT* pWidth, + _Out_ UINT* pHeight, + _Out_ D3DDDIFORMAT* pColorFormat) +{ + UNREFERENCED_PARAMETER(Flags); + + DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__)); + m_SystemDisplaySourceId = D3DDDI_ID_UNINITIALIZED; + + VIOGPU_ASSERT((TargetId < MAX_CHILDREN) || (TargetId == D3DDDI_ID_UNINITIALIZED)); + + if (TargetId == D3DDDI_ID_UNINITIALIZED) + { + for (UINT SourceIdx = 0; SourceIdx < MAX_VIEWS; ++SourceIdx) + { + if (m_CurrentModes[SourceIdx].FrameBuffer.Ptr != NULL) + { + m_SystemDisplaySourceId = SourceIdx; + break; + } + } + } + else + { + m_SystemDisplaySourceId = FindSourceForTarget(TargetId, FALSE); + } + + if (m_SystemDisplaySourceId == D3DDDI_ID_UNINITIALIZED) + { + { + return STATUS_UNSUCCESSFUL; + } + } + + if ((m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE90) || + (m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE270)) + { + *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width; + *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height; + } + else + { + *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width; + *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height; + } + + *pColorFormat = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat; + DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s ColorFormat = %d\n", __FUNCTION__, m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat)); + + return STATUS_SUCCESS; +} + +VOID VioGpuVidPN::SystemDisplayWrite(_In_reads_bytes_(SourceHeight* SourceStride) VOID* pSource, + _In_ UINT SourceWidth, + _In_ UINT SourceHeight, + _In_ UINT SourceStride, + _In_ INT PositionX, + _In_ INT PositionY) +{ + UNREFERENCED_PARAMETER(pSource); + UNREFERENCED_PARAMETER(SourceStride); + + RECT Rect; + Rect.left = PositionX; + Rect.top = PositionY; + Rect.right = Rect.left + SourceWidth; + Rect.bottom = Rect.top + SourceHeight; + + BLT_INFO DstBltInfo; + DstBltInfo.pBits = m_CurrentModes[m_SystemDisplaySourceId].FrameBuffer.Ptr; + DstBltInfo.Pitch = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Pitch; + DstBltInfo.BitsPerPel = BPPFromPixelFormat(m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat); + DstBltInfo.Offset.x = 0; + DstBltInfo.Offset.y = 0; + DstBltInfo.Rotation = m_CurrentModes[m_SystemDisplaySourceId].Rotation; + DstBltInfo.Width = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width; + DstBltInfo.Height = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height; + + BLT_INFO SrcBltInfo; + SrcBltInfo.pBits = pSource; + SrcBltInfo.Pitch = SourceStride; + SrcBltInfo.BitsPerPel = 32; + + SrcBltInfo.Offset.x = -PositionX; + SrcBltInfo.Offset.y = -PositionY; + SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY; + SrcBltInfo.Width = SourceWidth; + SrcBltInfo.Height = SourceHeight; + + BltBits(&DstBltInfo, + &SrcBltInfo, + &Rect); + +} + +#pragma code_seg(pop) // End Non-Paged Code \ No newline at end of file diff --git a/viogpu/viogpu3d/viogpu_vidpn.h b/viogpu/viogpu3d/viogpu_vidpn.h new file mode 100644 index 000000000..afd0b56e2 --- /dev/null +++ b/viogpu/viogpu3d/viogpu_vidpn.h @@ -0,0 +1,140 @@ +#pragma once + +#include "helper.h" + +class VioGpuAdapter; +class VioGpuAllocation; + +typedef struct _CURRENT_MODE +{ + DXGK_DISPLAY_INFORMATION DispInfo; + D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation; + D3DKMDT_VIDPN_PRESENT_PATH_SCALING Scaling; + UINT SrcModeWidth; + UINT SrcModeHeight; + struct _CURRENT_MODE_FLAGS + { + UINT SourceNotVisible : 1; + UINT FullscreenPresent : 1; + UINT FrameBufferIsActive : 1; + UINT DoNotMapOrUnmap : 1; + UINT IsInternal : 1; + UINT Unused : 27; + } Flags; + + PHYSICAL_ADDRESS ZeroedOutStart; + PHYSICAL_ADDRESS ZeroedOutEnd; + + union + { + VOID* Ptr; + ULONG64 Force8Bytes; + } FrameBuffer; +} CURRENT_MODE; + +class VioGpuVidPN +{ +public: + VioGpuVidPN(VioGpuAdapter *adapter); + ~VioGpuVidPN(); + + NTSTATUS Start(ULONG* pNumberOfViews, ULONG* pNumberOfChildren); + NTSTATUS AcquirePostDisplayOwnership(); + void ReleasePostDisplayOwnership(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, DXGK_DISPLAY_INFORMATION* pDisplayInfo); + void Powerdown(); + + NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const; + NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const; + + NTSTATUS CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn); + NTSTATUS UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath); + + NTSTATUS SetCurrentMode(ULONG Mode, CURRENT_MODE* pCurrentMode); + ULONG GetModeCount(void) { return m_ModeCount; } + VOID BlackOutScreen(CURRENT_MODE* pCurrentMod); + + NTSTATUS GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo); + + void CreateFrameBufferObj(PVIDEO_MODE_INFORMATION pModeInfo, CURRENT_MODE* pCurrentMode); + void DestroyFrameBufferObj(BOOLEAN bReset); + + BOOLEAN GpuObjectAttach(UINT res_id, VioGpuObj* obj); + PBYTE GetEdidData(UINT Idx); + + void SetVideoModeInfo(UINT Idx, PVIOGPU_DISP_MODE pModeInfo); + BOOLEAN GetDisplayInfo(void); + void ProcessEdid(void); + void FixEdid(void); + BOOLEAN GetEdids(void); + void AddEdidModes(void); + void SetCustomDisplay(_In_ USHORT xres, + _In_ USHORT yres); + + NTSTATUS EscapeCustomResoulution(VIOGPU_DISP_MODE* resolution); + + NTSTATUS IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn); + NTSTATUS RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn); + NTSTATUS RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology); + NTSTATUS RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); + NTSTATUS EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality); + NTSTATUS SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility); + NTSTATUS QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps); + + NTSTATUS SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, + _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags, + _Out_ UINT* pWidth, + _Out_ UINT* pHeight, + _Out_ D3DDDIFORMAT* pColorFormat); + VOID SystemDisplayWrite(_In_reads_bytes_(SourceHeight* SourceStride) VOID* pSource, + _In_ UINT SourceWidth, + _In_ UINT SourceHeight, + _In_ UINT SourceStride, + _In_ INT PositionX, + _In_ INT PositionY); + + void Flip(); + static void FlipThread(void *ctx); + + NTSTATUS SetVidPnSourceAddress(const DXGKARG_SETVIDPNSOURCEADDRESS* pSetVidPnSourceAddress); + +private: + NTSTATUS SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode, + CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath); + NTSTATUS AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes); + NTSTATUS AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface, + D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet, + D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); + NTSTATUS AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface, + D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet, + _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo, + D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId); + D3DDDI_VIDEO_PRESENT_SOURCE_ID FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero); + VOID BuildVideoSignalInfo(D3DKMDT_VIDEO_SIGNAL_INFO* pVideoSignalInfo, PVIDEO_MODE_INFORMATION pModeInfo); + + + VioGpuAdapter *m_pAdapter; + DXGKRNL_INTERFACE* m_pDxgkInterface; + + CURRENT_MODE m_CurrentModes[MAX_VIEWS]; + + PVIDEO_MODE_INFORMATION m_ModeInfo; + ULONG m_ModeCount; + PUSHORT m_ModeNumbers; + USHORT m_CurrentMode; + USHORT m_CustomMode; + BYTE m_EDIDs[MAX_CHILDREN][EDID_V1_BLOCK_SIZE]; + BOOLEAN m_bEDID; + + DXGK_DISPLAY_INFORMATION m_SystemDisplayInfo; + D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SystemDisplaySourceId; + + VioGpuObj* m_pFrameBuf; + + PHYSICAL_ADDRESS m_sourceAddress = { 0 }; + VioGpuAllocation* m_sourceRes = NULL; + volatile LONG m_shouldFlip = 0; + + PETHREAD m_pFlipThread; + BOOL m_shouldFlipStop = false; +}; +