EvanZhu0721 / 公开仓库
SBMS
SBMS complete the calculation rules for the default logical desktop topology relationship and the physical dimensions of the displays in the Windows multi-screen collaboration system.
driver/Driver.cpp17.8 KB
1
#define NOMINMAX2
3
#include <windows.h>4
#include <wdf.h>5
#include <iddcx.h>6
#include <dxgi1_5.h>7
#include <d3d11.h>8
#include <new>9
10
EVT_WDF_DRIVER_DEVICE_ADD DeviceAdd;11
EVT_WDF_DEVICE_D0_ENTRY DeviceD0Entry;12
EVT_WDF_OBJECT_CONTEXT_CLEANUP MonitorCleanup;13
EVT_IDD_CX_ADAPTER_INIT_FINISHED AdapterInitFinished;14
EVT_IDD_CX_ADAPTER_COMMIT_MODES AdapterCommitModes;15
EVT_IDD_CX_PARSE_MONITOR_DESCRIPTION ParseMonitorDescription;16
EVT_IDD_CX_MONITOR_GET_DEFAULT_DESCRIPTION_MODES GetDefaultMonitorModes;17
EVT_IDD_CX_MONITOR_QUERY_TARGET_MODES QueryTargetModes;18
EVT_IDD_CX_MONITOR_ASSIGN_SWAPCHAIN AssignSwapChain;19
EVT_IDD_CX_MONITOR_UNASSIGN_SWAPCHAIN UnassignSwapChain;20
21
namespace22
{23
constexpr UINT kMaximumDimension = 16384;24
constexpr UINT kMaximumRefreshRate = 1000;25
constexpr UINT kMaximumMonitors = 16;26
constexpr wchar_t kSessionGate[] = L"Global\\SBMSSession-v7";27
constexpr UINT kGateMagic = 0x53424737;28
constexpr UINT kProtocolVersion = 7;29
30
struct GateHeader31
{32
UINT magic;33
UINT version;34
UINT count;35
UINT reserved;36
};37
38
struct GateEntry39
{40
UINT connectorIndex;41
UINT width;42
UINT height;43
UINT refreshNumerator;44
UINT refreshDenominator;45
};46
47
struct GateConfig48
{49
GateHeader header;50
GateEntry entries[kMaximumMonitors];51
};52
53
static_assert(sizeof(GateHeader) == 16);54
static_assert(sizeof(GateEntry) == 20);55
static_assert(sizeof(GateConfig) == 336);56
57
struct ModeConfig58
{59
UINT connectorIndex;60
UINT width;61
UINT height;62
UINT refreshNumerator;63
UINT refreshDenominator;64
};65
66
// One permanent monitor identity. Changing either value makes Windows treat the67
// virtual monitor as new hardware and loses its saved desktop placement.68
constexpr GUID kMonitorContainerId =69
{0x67453031, 0x7ba9, 0x4d45, {0x8f, 0x0b, 0x72, 0x1d, 0xb4, 0x61, 0x62, 0x42}};70
71
GUID MonitorContainerId(UINT connectorIndex)72
{73
GUID id = kMonitorContainerId;74
id.Data1 ^= connectorIndex;75
return id;76
}77
78
struct Drain79
{80
IDDCX_SWAPCHAIN swapChain{};81
ID3D11Device* d3dDevice{};82
HANDLE frameAvailable{};83
HANDLE stop{};84
HANDLE thread{};85
volatile LONG ownership{};86
};87
88
struct DeviceState89
{90
WDFDEVICE device{};91
IDDCX_ADAPTER adapter{};92
};93
94
struct MonitorState95
{96
Drain* drain{};97
ModeConfig mode{};98
};99
100
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DeviceState, GetDeviceState);101
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MonitorState, GetMonitorState);102
103
bool ValidateMode(104
UINT connectorIndex,105
UINT width,106
UINT height,107
UINT refreshNumerator,108
UINT refreshDenominator,109
ModeConfig& mode)110
{111
if (connectorIndex >= kMaximumMonitors ||112
width == 0 || height == 0 ||113
width > kMaximumDimension || height > kMaximumDimension ||114
refreshNumerator == 0 || refreshDenominator == 0)115
{116
return false;117
}118
const UINT64 maximumNumerator =119
static_cast<UINT64>(refreshDenominator) * kMaximumRefreshRate;120
if (refreshNumerator < refreshDenominator ||121
refreshNumerator > maximumNumerator ||122
static_cast<UINT64>(height) * refreshNumerator > MAXUINT32)123
{124
return false;125
}126
127
mode.connectorIndex = connectorIndex;128
mode.width = width;129
mode.height = height;130
mode.refreshNumerator = refreshNumerator;131
mode.refreshDenominator = refreshDenominator;132
return true;133
}134
135
bool ReadSessionConfig(ModeConfig (&modes)[kMaximumMonitors], UINT& count)136
{137
HANDLE gate = OpenFileMappingW(FILE_MAP_READ, FALSE, kSessionGate);138
if (gate == nullptr)139
{140
return false;141
}142
const auto* config = static_cast<const GateConfig*>(143
MapViewOfFile(gate, FILE_MAP_READ, 0, 0, sizeof(GateConfig)));144
bool valid = false;145
if (config != nullptr &&146
config->header.magic == kGateMagic &&147
config->header.version == kProtocolVersion &&148
config->header.count > 0 &&149
config->header.count <= kMaximumMonitors)150
{151
valid = true;152
UINT connectorMask = 0;153
for (UINT index = 0; index < config->header.count; ++index)154
{155
const GateEntry& entry = config->entries[index];156
if (entry.connectorIndex >= kMaximumMonitors)157
{158
valid = false;159
break;160
}161
const UINT connectorBit = 1u << entry.connectorIndex;162
if ((connectorMask & connectorBit) != 0 ||163
!ValidateMode(164
entry.connectorIndex,165
entry.width,166
entry.height,167
entry.refreshNumerator,168
entry.refreshDenominator,169
modes[index]))170
{171
valid = false;172
break;173
}174
connectorMask |= connectorBit;175
}176
if (valid)177
{178
count = config->header.count;179
}180
}181
if (config != nullptr) UnmapViewOfFile(config);182
CloseHandle(gate);183
return valid;184
}185
186
void FillSignal(187
DISPLAYCONFIG_VIDEO_SIGNAL_INFO& signal,188
const ModeConfig& config,189
bool monitorMode)190
{191
signal.activeSize.cx = config.width;192
signal.activeSize.cy = config.height;193
signal.totalSize.cx = config.width;194
signal.totalSize.cy = config.height;195
signal.vSyncFreq.Numerator = config.refreshNumerator;196
signal.vSyncFreq.Denominator = config.refreshDenominator;197
signal.hSyncFreq.Numerator = config.height * config.refreshNumerator;198
signal.hSyncFreq.Denominator = config.refreshDenominator;199
signal.pixelRate =200
static_cast<UINT64>(config.width) *201
config.height *202
config.refreshNumerator /203
config.refreshDenominator;204
signal.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;205
signal.AdditionalSignalInfo.videoStandard = 255;206
signal.AdditionalSignalInfo.vSyncFreqDivider = monitorMode ? 0 : 1;207
}208
209
IDDCX_MONITOR_MODE MonitorMode(210
const ModeConfig& config,211
IDDCX_MONITOR_MODE_ORIGIN origin)212
{213
IDDCX_MONITOR_MODE mode{};214
mode.Size = sizeof(mode);215
mode.Origin = origin;216
FillSignal(mode.MonitorVideoSignalInfo, config, true);217
return mode;218
}219
220
IDDCX_TARGET_MODE TargetMode(const ModeConfig& config)221
{222
IDDCX_TARGET_MODE mode{};223
mode.Size = sizeof(mode);224
FillSignal(mode.TargetVideoSignalInfo.targetVideoSignalInfo, config, false);225
return mode;226
}227
228
void DestroyDrain(Drain* drain)229
{230
if (drain->thread != nullptr) CloseHandle(drain->thread);231
if (drain->stop != nullptr) CloseHandle(drain->stop);232
if (drain->d3dDevice != nullptr) drain->d3dDevice->Release();233
delete drain;234
}235
236
DWORD WINAPI DrainFrames(void* argument)237
{238
auto* drain = static_cast<Drain*>(argument);239
240
for (;;)241
{242
if (WaitForSingleObject(drain->stop, 0) == WAIT_OBJECT_0)243
{244
break;245
}246
247
IDARG_OUT_RELEASEANDACQUIREBUFFER buffer{};248
const HRESULT result =249
IddCxSwapChainReleaseAndAcquireBuffer(drain->swapChain, &buffer);250
251
if (result == E_PENDING)252
{253
const HANDLE handles[] = {drain->frameAvailable, drain->stop};254
const DWORD wait = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);255
if (wait == WAIT_OBJECT_0)256
{257
continue;258
}259
break;260
}261
262
if (FAILED(result))263
{264
break;265
}266
267
if (buffer.MetaData.pSurface != nullptr)268
{269
buffer.MetaData.pSurface->Release();270
}271
272
if (FAILED(IddCxSwapChainFinishedProcessingFrame(drain->swapChain)))273
{274
break;275
}276
}277
278
WdfObjectDelete(drain->swapChain);279
drain->swapChain = nullptr;280
if (InterlockedCompareExchange(&drain->ownership, 2, 0) == 1)281
{282
DestroyDrain(drain);283
}284
return 0;285
}286
287
void StopDrain(MonitorState* monitor)288
{289
if (monitor == nullptr || monitor->drain == nullptr)290
{291
return;292
}293
294
Drain* drain = monitor->drain;295
monitor->drain = nullptr;296
SetEvent(drain->stop);297
if (drain->thread != nullptr)298
{299
if (WaitForSingleObject(drain->thread, 5000) != WAIT_OBJECT_0)300
{301
// Either the worker observes state 1 and destroys itself, or it302
// already published state 2 and cleanup remains here.303
if (InterlockedCompareExchange(&drain->ownership, 1, 0) != 2)304
{305
return;306
}307
}308
}309
DestroyDrain(drain);310
}311
312
bool StartDrain(313
MonitorState* monitor,314
IDDCX_SWAPCHAIN swapChain,315
LUID renderAdapter,316
HANDLE frameAvailable)317
{318
IDXGIFactory5* factory = nullptr;319
IDXGIAdapter1* adapter = nullptr;320
IDXGIDevice* dxgiDevice = nullptr;321
ID3D11Device* d3dDevice = nullptr;322
323
HRESULT result = CreateDXGIFactory2(0, IID_PPV_ARGS(&factory));324
if (SUCCEEDED(result))325
{326
result = factory->EnumAdapterByLuid(renderAdapter, IID_PPV_ARGS(&adapter));327
}328
if (SUCCEEDED(result))329
{330
result = D3D11CreateDevice(331
adapter,332
D3D_DRIVER_TYPE_UNKNOWN,333
nullptr,334
D3D11_CREATE_DEVICE_BGRA_SUPPORT,335
nullptr,336
0,337
D3D11_SDK_VERSION,338
&d3dDevice,339
nullptr,340
nullptr);341
}342
if (SUCCEEDED(result))343
{344
result = d3dDevice->QueryInterface(IID_PPV_ARGS(&dxgiDevice));345
}346
if (SUCCEEDED(result))347
{348
IDARG_IN_SWAPCHAINSETDEVICE setDevice{};349
setDevice.pDevice = dxgiDevice;350
result = IddCxSwapChainSetDevice(swapChain, &setDevice);351
}352
353
if (dxgiDevice != nullptr) dxgiDevice->Release();354
if (adapter != nullptr) adapter->Release();355
if (factory != nullptr) factory->Release();356
357
if (FAILED(result))358
{359
if (d3dDevice != nullptr) d3dDevice->Release();360
return false;361
}362
363
auto* drain = new (std::nothrow) Drain{};364
if (drain == nullptr)365
{366
d3dDevice->Release();367
return false;368
}369
370
drain->swapChain = swapChain;371
drain->d3dDevice = d3dDevice;372
drain->frameAvailable = frameAvailable;373
drain->stop = CreateEventW(nullptr, TRUE, FALSE, nullptr);374
if (drain->stop != nullptr)375
{376
drain->thread = CreateThread(nullptr, 0, DrainFrames, drain, 0, nullptr);377
}378
if (drain->thread == nullptr)379
{380
if (drain->stop != nullptr) CloseHandle(drain->stop);381
d3dDevice->Release();382
delete drain;383
return false;384
}385
386
monitor->drain = drain;387
return true;388
}389
390
NTSTATUS ReportMonitor(DeviceState* state, const ModeConfig& mode)391
{392
WDF_OBJECT_ATTRIBUTES attributes;393
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, MonitorState);394
attributes.EvtCleanupCallback = MonitorCleanup;395
396
IDDCX_MONITOR_INFO info{};397
info.Size = sizeof(info);398
info.MonitorType = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER;399
info.ConnectorIndex = mode.connectorIndex;400
info.MonitorContainerId = MonitorContainerId(mode.connectorIndex);401
info.MonitorDescription.Size = sizeof(info.MonitorDescription);402
info.MonitorDescription.Type = IDDCX_MONITOR_DESCRIPTION_TYPE_EDID;403
info.MonitorDescription.DataSize = 0;404
info.MonitorDescription.pData = nullptr;405
406
IDARG_IN_MONITORCREATE input{};407
input.ObjectAttributes = &attributes;408
input.pMonitorInfo = &info;409
IDARG_OUT_MONITORCREATE output{};410
const NTSTATUS createStatus =411
IddCxMonitorCreate(state->adapter, &input, &output);412
if (!NT_SUCCESS(createStatus))413
{414
return createStatus;415
}416
417
MonitorState* monitorState = GetMonitorState(output.MonitorObject);418
monitorState->mode = mode;419
420
IDARG_OUT_MONITORARRIVAL arrival{};421
const NTSTATUS arrivalStatus =422
IddCxMonitorArrival(output.MonitorObject, &arrival);423
if (!NT_SUCCESS(arrivalStatus))424
{425
WdfObjectDelete(output.MonitorObject);426
return arrivalStatus;427
}428
429
return STATUS_SUCCESS;430
}431
432
NTSTATUS ReportMonitors(DeviceState* state)433
{434
ModeConfig modes[kMaximumMonitors]{};435
UINT count = 0;436
if (!ReadSessionConfig(modes, count))437
{438
return STATUS_INVALID_PARAMETER;439
}440
441
for (UINT index = 0; index < count; ++index)442
{443
const NTSTATUS status = ReportMonitor(state, modes[index]);444
if (!NT_SUCCESS(status))445
{446
return status;447
}448
}449
return STATUS_SUCCESS;450
}451
452
void InitAdapter(DeviceState* state)453
{454
if (state->adapter != nullptr)455
{456
return;457
}458
459
IDDCX_ENDPOINT_VERSION version{};460
version.Size = sizeof(version);461
version.MajorVer = 1;462
463
IDDCX_ADAPTER_CAPS caps{};464
caps.Size = sizeof(caps);465
caps.Flags = IDDCX_ADAPTER_FLAGS_USE_SMALLEST_MODE;466
caps.MaxMonitorsSupported = kMaximumMonitors;467
caps.EndPointDiagnostics.Size = sizeof(caps.EndPointDiagnostics);468
caps.EndPointDiagnostics.GammaSupport = IDDCX_FEATURE_IMPLEMENTATION_NONE;469
caps.EndPointDiagnostics.TransmissionType = IDDCX_TRANSMISSION_TYPE_WIRED_OTHER;470
caps.EndPointDiagnostics.pEndPointFriendlyName = L"SBMS Display";471
caps.EndPointDiagnostics.pEndPointManufacturerName = L"SBMS";472
caps.EndPointDiagnostics.pEndPointModelName = L"SBMS IDD";473
caps.EndPointDiagnostics.pFirmwareVersion = &version;474
caps.EndPointDiagnostics.pHardwareVersion = &version;475
476
WDF_OBJECT_ATTRIBUTES attributes;477
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DeviceState);478
479
IDARG_IN_ADAPTER_INIT input{};480
input.WdfDevice = state->device;481
input.pCaps = ∩︀482
input.ObjectAttributes = &attributes;483
IDARG_OUT_ADAPTER_INIT output{};484
if (NT_SUCCESS(IddCxAdapterInitAsync(&input, &output)))485
{486
state->adapter = output.AdapterObject;487
DeviceState* adapterState = GetDeviceState(output.AdapterObject);488
adapterState->device = state->device;489
adapterState->adapter = output.AdapterObject;490
}491
}492
}493
494
extern "C" DRIVER_INITIALIZE DriverEntry;495
496
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, void*)497
{498
return TRUE;499
}500
501
extern "C" NTSTATUS DriverEntry(502
PDRIVER_OBJECT driverObject,503
PUNICODE_STRING registryPath)504
{505
WDF_DRIVER_CONFIG config;506
WDF_DRIVER_CONFIG_INIT(&config, DeviceAdd);507
WDF_OBJECT_ATTRIBUTES attributes;508
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);509
return WdfDriverCreate(510
driverObject, registryPath, &attributes, &config, WDF_NO_HANDLE);511
}512
513
NTSTATUS DeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT deviceInit)514
{515
UNREFERENCED_PARAMETER(driver);516
517
WDF_PNPPOWER_EVENT_CALLBACKS power;518
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&power);519
power.EvtDeviceD0Entry = DeviceD0Entry;520
WdfDeviceInitSetPnpPowerEventCallbacks(deviceInit, &power);521
522
IDD_CX_CLIENT_CONFIG idd;523
IDD_CX_CLIENT_CONFIG_INIT(&idd);524
idd.EvtIddCxAdapterInitFinished = AdapterInitFinished;525
idd.EvtIddCxAdapterCommitModes = AdapterCommitModes;526
idd.EvtIddCxParseMonitorDescription = ParseMonitorDescription;527
idd.EvtIddCxMonitorGetDefaultDescriptionModes = GetDefaultMonitorModes;528
idd.EvtIddCxMonitorQueryTargetModes = QueryTargetModes;529
idd.EvtIddCxMonitorAssignSwapChain = AssignSwapChain;530
idd.EvtIddCxMonitorUnassignSwapChain = UnassignSwapChain;531
532
NTSTATUS status = IddCxDeviceInitConfig(deviceInit, &idd);533
if (!NT_SUCCESS(status))534
{535
return status;536
}537
538
WDF_OBJECT_ATTRIBUTES attributes;539
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DeviceState);540
WDFDEVICE device = nullptr;541
status = WdfDeviceCreate(&deviceInit, &attributes, &device);542
if (!NT_SUCCESS(status))543
{544
return status;545
}546
547
DeviceState* state = GetDeviceState(device);548
state->device = device;549
status = IddCxDeviceInitialize(device);550
return status;551
}552
553
NTSTATUS DeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previousState)554
{555
UNREFERENCED_PARAMETER(previousState);556
InitAdapter(GetDeviceState(device));557
return STATUS_SUCCESS;558
}559
560
void MonitorCleanup(WDFOBJECT object)561
{562
StopDrain(GetMonitorState(object));563
}564
565
NTSTATUS AdapterInitFinished(566
IDDCX_ADAPTER adapter,567
const IDARG_IN_ADAPTER_INIT_FINISHED* input)568
{569
if (NT_SUCCESS(input->AdapterInitStatus))570
{571
return ReportMonitors(GetDeviceState(adapter));572
}573
return input->AdapterInitStatus;574
}575
576
NTSTATUS AdapterCommitModes(577
IDDCX_ADAPTER adapter,578
const IDARG_IN_COMMITMODES* input)579
{580
UNREFERENCED_PARAMETER(adapter);581
UNREFERENCED_PARAMETER(input);582
return STATUS_SUCCESS;583
}584
585
NTSTATUS ParseMonitorDescription(586
const IDARG_IN_PARSEMONITORDESCRIPTION* input,587
IDARG_OUT_PARSEMONITORDESCRIPTION* output)588
{589
UNREFERENCED_PARAMETER(input);590
UNREFERENCED_PARAMETER(output);591
return STATUS_INVALID_PARAMETER;592
}593
594
NTSTATUS GetDefaultMonitorModes(595
IDDCX_MONITOR monitor,596
const IDARG_IN_GETDEFAULTDESCRIPTIONMODES* input,597
IDARG_OUT_GETDEFAULTDESCRIPTIONMODES* output)598
{599
UNREFERENCED_PARAMETER(monitor);600
output->DefaultMonitorModeBufferOutputCount = 1;601
if (input->DefaultMonitorModeBufferInputCount == 0)602
{603
return STATUS_SUCCESS;604
}605
if (input->DefaultMonitorModeBufferInputCount < 1)606
{607
return STATUS_BUFFER_TOO_SMALL;608
}609
610
input->pDefaultMonitorModes[0] =611
MonitorMode(GetMonitorState(monitor)->mode, IDDCX_MONITOR_MODE_ORIGIN_DRIVER);612
output->PreferredMonitorModeIdx = 0;613
return STATUS_SUCCESS;614
}615
616
NTSTATUS QueryTargetModes(617
IDDCX_MONITOR monitor,618
const IDARG_IN_QUERYTARGETMODES* input,619
IDARG_OUT_QUERYTARGETMODES* output)620
{621
UNREFERENCED_PARAMETER(monitor);622
output->TargetModeBufferOutputCount = 1;623
if (input->TargetModeBufferInputCount >= 1)624
{625
input->pTargetModes[0] = TargetMode(GetMonitorState(monitor)->mode);626
}627
return STATUS_SUCCESS;628
}629
630
NTSTATUS AssignSwapChain(631
IDDCX_MONITOR monitor,632
const IDARG_IN_SETSWAPCHAIN* input)633
{634
MonitorState* state = GetMonitorState(monitor);635
StopDrain(state);636
if (!StartDrain(637
state,638
input->hSwapChain,639
input->RenderAdapterLuid,640
input->hNextSurfaceAvailable))641
{642
WdfObjectDelete(input->hSwapChain);643
}644
return STATUS_SUCCESS;645
}646
647
NTSTATUS UnassignSwapChain(IDDCX_MONITOR monitor)648
{649
StopDrain(GetMonitorState(monitor));650
return STATUS_SUCCESS;651
}652