├── IddSampleDriver
├── IddSampleDriver.inf
├── readme.md
├── IddSampleDriver.vcxproj.filters
├── Trace.h
├── IddSampleDriver.sln
├── Driver.h
├── IddSampleDriver.vcxproj
└── Driver.cpp
├── CppProperties.json
├── option.txt
├── .gitattributes
├── IddSampleDriver.sln
├── .gitignore
└── README.md
/IddSampleDriver/IddSampleDriver.inf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ge9/IddSampleDriver/HEAD/IddSampleDriver/IddSampleDriver.inf
--------------------------------------------------------------------------------
/CppProperties.json:
--------------------------------------------------------------------------------
1 | {
2 | "configurations": [
3 | {
4 | "inheritEnvironments": [
5 | "msvc_x64"
6 | ],
7 | "name": "x64-Debug",
8 | "includePath": [
9 | "${env.INCLUDE}",
10 | "${workspaceRoot}\\**"
11 | ],
12 | "defines": [
13 | "WIN32",
14 | "_DEBUG",
15 | "UNICODE",
16 | "_UNICODE"
17 | ],
18 | "intelliSenseMode": "windows-msvc-x64"
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/IddSampleDriver/readme.md:
--------------------------------------------------------------------------------
1 | # Get 5 virtual monitors for the price of zero!
2 |
3 | # Steps (for experienced pros only!!!)
4 | 1. Download the latest release as a zip file.
5 |
6 | 2. As an administrator, Run the *.bat file to add the driver certificate as a trusted root certificate.
7 |
8 | 3. Don't install the inf. Open device manager, click on any device, then click on the "Action" menu and click "Add Legacy Hardware"
9 |
10 | 4. Select "Add hardware from a list (Advanced)" and then select Display adapters
11 |
12 | 5. Click "Have Disk..." and click the "Browse..." button. Navigate to the extracted files and select the inf file.
13 |
14 | 6. You are done! Go to display settings to customize the resolution of the additional displays. These displays show up in Oculus and should be able to be streamed from.
--------------------------------------------------------------------------------
/option.txt:
--------------------------------------------------------------------------------
1 | 1
2 | #lines beginning with "#" are ignored (comment)
3 | #the first line must be a positive integer (small number (<5) is recommended)), NOT comment
4 | #(currently) the location of this file must be "C:\IddSampleDriver\option.txt" (hard-coded)
5 | #numbers should be separated by comma
6 | #spaces before number are allowed
7 | 640, 480, 60
8 | 800, 600, 60
9 | 1024, 768, 60
10 | 1152, 864, 60
11 | 1280, 600, 60
12 | 1280, 720, 60
13 | 1280, 768, 60
14 | 1280, 800, 60
15 | 1280, 960, 60
16 | 1280, 1024, 60
17 | 1360, 768, 60
18 | 1366, 768, 60
19 | 1400, 1050, 60
20 | 1440, 900, 60
21 | 1600, 900, 60
22 | 1680, 1050, 60
23 | 1600, 1024, 60
24 | 1920, 1080, 60
25 | 1920, 1200, 60
26 | 1920, 1440, 60
27 | 2560, 1440, 60
28 | 2560, 1600, 60
29 | 2880, 1620, 60
30 | 2880, 1800, 60
31 | 3008, 1692, 60
32 | 3200, 1800, 60
33 | 3200, 2400, 60
34 | 3840, 2160, 60
35 | 3840, 2400, 60
36 | 4096, 2304, 60
37 | 4096, 2560, 60
38 | 5120, 2880, 60
39 | 6016, 3384, 60
40 | 7680, 4320, 60
41 |
--------------------------------------------------------------------------------
/IddSampleDriver/IddSampleDriver.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {8E41214B-6785-4CFE-B992-037D68949A14}
18 | inf;inv;inx;mof;mc;
19 |
20 |
21 |
22 |
23 | Driver Files
24 |
25 |
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 |
35 |
36 | Source Files
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/IddSampleDriver/Trace.h:
--------------------------------------------------------------------------------
1 | /*++
2 |
3 | Module Name:
4 |
5 | Internal.h
6 |
7 | Abstract:
8 |
9 | This module contains the local type definitions for the
10 | driver.
11 |
12 | Environment:
13 |
14 | Windows User-Mode Driver Framework 2
15 |
16 | --*/
17 |
18 | //
19 | // Define the tracing flags.
20 | //
21 | // Tracing GUID - b254994f-46e6-4718-80a0-0a3aa50d6ce4
22 | //
23 |
24 | #define WPP_CONTROL_GUIDS \
25 | WPP_DEFINE_CONTROL_GUID( \
26 | MyDriver1TraceGuid, (b254994f,46e6,4718,80a0,0a3aa50d6ce4), \
27 | \
28 | WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \
29 | WPP_DEFINE_BIT(TRACE_DRIVER) \
30 | WPP_DEFINE_BIT(TRACE_DEVICE) \
31 | WPP_DEFINE_BIT(TRACE_QUEUE) \
32 | )
33 |
34 | #define WPP_FLAG_LEVEL_LOGGER(flag, level) \
35 | WPP_LEVEL_LOGGER(flag)
36 |
37 | #define WPP_FLAG_LEVEL_ENABLED(flag, level) \
38 | (WPP_LEVEL_ENABLED(flag) && \
39 | WPP_CONTROL(WPP_BIT_ ## flag).Level >= level)
40 |
41 | #define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \
42 | WPP_LEVEL_LOGGER(flags)
43 |
44 | #define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \
45 | (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
46 |
47 | //
48 | // This comment block is scanned by the trace preprocessor to define our
49 | // Trace function.
50 | //
51 | // begin_wpp config
52 | // FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...);
53 | // FUNC TraceEvents(LEVEL, FLAGS, MSG, ...);
54 | // end_wpp
55 |
56 | //
57 | //
58 | // Driver specific #defines
59 | //
60 | #if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0
61 | // TODO: Update the name of the tracing provider
62 | #define MYDRIVER_TRACING_ID L"Microsoft\\UMDF2.0\\IddSampleDriver V1.0"
63 | #endif
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/IddSampleDriver.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31129.286
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IddSampleDriver", "IddSampleDriver\IddSampleDriver.vcxproj", "{2D54CB75-8B17-4F11-97DC-847B0244CD46}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|ARM = Debug|ARM
11 | Debug|ARM64 = Debug|ARM64
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|ARM = Release|ARM
15 | Release|ARM64 = Release|ARM64
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.ActiveCfg = Debug|x64
21 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Build.0 = Debug|x64
22 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Deploy.0 = Debug|x64
23 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.ActiveCfg = Debug|ARM64
24 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Build.0 = Debug|ARM64
25 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Deploy.0 = Debug|ARM64
26 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.ActiveCfg = Debug|x64
27 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Build.0 = Debug|x64
28 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Deploy.0 = Debug|x64
29 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.ActiveCfg = Debug|Win32
30 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Build.0 = Debug|Win32
31 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Deploy.0 = Debug|Win32
32 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.ActiveCfg = Release|ARM
33 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Build.0 = Release|ARM
34 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Deploy.0 = Release|ARM
35 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.ActiveCfg = Release|ARM64
36 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Build.0 = Release|ARM64
37 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Deploy.0 = Release|ARM64
38 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.ActiveCfg = Release|x64
39 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.Build.0 = Release|x64
40 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.Deploy.0 = Release|x64
41 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.ActiveCfg = Release|Win32
42 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Build.0 = Release|Win32
43 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Deploy.0 = Release|Win32
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | GlobalSection(ExtensibilityGlobals) = postSolution
49 | SolutionGuid = {DE75497E-BE4F-4215-8345-84C5F8358E3B}
50 | EndGlobalSection
51 | EndGlobal
52 |
--------------------------------------------------------------------------------
/IddSampleDriver/IddSampleDriver.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31129.286
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IddSampleDriver", "IddSampleDriver.vcxproj", "{2D54CB75-8B17-4F11-97DC-847B0244CD46}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|ARM = Debug|ARM
11 | Debug|ARM64 = Debug|ARM64
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|ARM = Release|ARM
15 | Release|ARM64 = Release|ARM64
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.ActiveCfg = Debug|ARM
21 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Build.0 = Debug|ARM
22 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Deploy.0 = Debug|ARM
23 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.ActiveCfg = Debug|ARM64
24 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Build.0 = Debug|ARM64
25 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Deploy.0 = Debug|ARM64
26 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.ActiveCfg = Debug|x64
27 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Build.0 = Debug|x64
28 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Deploy.0 = Debug|x64
29 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.ActiveCfg = Debug|Win32
30 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Build.0 = Debug|Win32
31 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Deploy.0 = Debug|Win32
32 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.ActiveCfg = Release|ARM
33 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Build.0 = Release|ARM
34 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Deploy.0 = Release|ARM
35 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.ActiveCfg = Release|ARM64
36 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Build.0 = Release|ARM64
37 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Deploy.0 = Release|ARM64
38 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.ActiveCfg = Release|x64
39 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.Build.0 = Release|x64
40 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.Deploy.0 = Release|x64
41 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.ActiveCfg = Release|Win32
42 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Build.0 = Release|Win32
43 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Deploy.0 = Release|Win32
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | GlobalSection(ExtensibilityGlobals) = postSolution
49 | SolutionGuid = {9A8BE7D9-9F0F-40A2-BA2D-8AE9E35890DB}
50 | EndGlobalSection
51 | EndGlobal
52 |
--------------------------------------------------------------------------------
/IddSampleDriver/Driver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define NOMINMAX
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 |
18 | #include "Trace.h"
19 |
20 | namespace Microsoft
21 | {
22 | namespace WRL
23 | {
24 | namespace Wrappers
25 | {
26 | // Adds a wrapper for thread handles to the existing set of WRL handle wrapper classes
27 | typedef HandleT Thread;
28 | }
29 | }
30 | }
31 |
32 | namespace Microsoft
33 | {
34 | namespace IndirectDisp
35 | {
36 | ///
37 | /// Manages the creation and lifetime of a Direct3D render device.
38 | ///
39 | struct Direct3DDevice
40 | {
41 | Direct3DDevice(LUID AdapterLuid);
42 | Direct3DDevice();
43 | HRESULT Init();
44 |
45 | LUID AdapterLuid;
46 | Microsoft::WRL::ComPtr DxgiFactory;
47 | Microsoft::WRL::ComPtr Adapter;
48 | Microsoft::WRL::ComPtr Device;
49 | Microsoft::WRL::ComPtr DeviceContext;
50 | };
51 |
52 | ///
53 | /// Manages a thread that consumes buffers from an indirect display swap-chain object.
54 | ///
55 | class SwapChainProcessor
56 | {
57 | public:
58 | SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, std::shared_ptr Device, HANDLE NewFrameEvent);
59 | ~SwapChainProcessor();
60 |
61 | private:
62 | static DWORD CALLBACK RunThread(LPVOID Argument);
63 |
64 | void Run();
65 | void RunCore();
66 |
67 | public:
68 | IDDCX_SWAPCHAIN m_hSwapChain;
69 | std::shared_ptr m_Device;
70 | HANDLE m_hAvailableBufferEvent;
71 | Microsoft::WRL::Wrappers::Thread m_hThread;
72 | Microsoft::WRL::Wrappers::Event m_hTerminateEvent;
73 | };
74 |
75 | ///
76 | /// Provides a sample implementation of an indirect display driver.
77 | ///
78 | class IndirectDeviceContext
79 | {
80 | public:
81 | IndirectDeviceContext(_In_ WDFDEVICE WdfDevice);
82 | virtual ~IndirectDeviceContext();
83 |
84 | void InitAdapter();
85 | void FinishInit();
86 |
87 | void CreateMonitor(unsigned int index);
88 |
89 | void AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent);
90 | void UnassignSwapChain();
91 |
92 | protected:
93 |
94 | WDFDEVICE m_WdfDevice;
95 | IDDCX_ADAPTER m_Adapter;
96 | IDDCX_MONITOR m_Monitor;
97 | IDDCX_MONITOR m_Monitor2;
98 |
99 | std::unique_ptr m_ProcessingThread;
100 |
101 | public:
102 | static const DISPLAYCONFIG_VIDEO_SIGNAL_INFO s_KnownMonitorModes[];
103 | static const BYTE s_KnownMonitorEdid[];
104 | };
105 | }
106 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Windows Store app package directory
170 | AppPackages/
171 | BundleArtifacts/
172 |
173 | # Visual Studio cache files
174 | # files ending in .cache can be ignored
175 | *.[Cc]ache
176 | # but keep track of directories ending in .cache
177 | !*.[Cc]ache/
178 |
179 | # Others
180 | ClientBin/
181 | [Ss]tyle[Cc]op.*
182 | ~$*
183 | *~
184 | *.dbmdl
185 | *.dbproj.schemaview
186 | *.pfx
187 | *.publishsettings
188 | node_modules/
189 | orleans.codegen.cs
190 |
191 | # RIA/Silverlight projects
192 | Generated_Code/
193 |
194 | # Backup & report files from converting an old project file
195 | # to a newer Visual Studio version. Backup files are not needed,
196 | # because we have git ;-)
197 | _UpgradeReport_Files/
198 | Backup*/
199 | UpgradeLog*.XML
200 | UpgradeLog*.htm
201 |
202 | # SQL Server files
203 | *.mdf
204 | *.ldf
205 |
206 | # Business Intelligence projects
207 | *.rdl.data
208 | *.bim.layout
209 | *.bim_*.settings
210 |
211 | # Microsoft Fakes
212 | FakesAssemblies/
213 |
214 | # GhostDoc plugin setting file
215 | *.GhostDoc.xml
216 |
217 | # Node.js Tools for Visual Studio
218 | .ntvs_analysis.dat
219 |
220 | # Visual Studio 6 build log
221 | *.plg
222 |
223 | # Visual Studio 6 workspace options file
224 | *.opt
225 |
226 | # Visual Studio LightSwitch build output
227 | **/*.HTMLClient/GeneratedArtifacts
228 | **/*.DesktopClient/GeneratedArtifacts
229 | **/*.DesktopClient/ModelManifest.xml
230 | **/*.Server/GeneratedArtifacts
231 | **/*.Server/ModelManifest.xml
232 | _Pvt_Extensions
233 |
234 | # LightSwitch generated files
235 | GeneratedArtifacts/
236 | ModelManifest.xml
237 |
238 | # Paket dependency manager
239 | .paket/paket.exe
240 |
241 | # FAKE - F# Make
242 | .fake/
243 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | License MIT and CC0 or Public Domain (for changes I made, check with Microsoft for their license), whichever is least restrictive -- Use it
2 |
3 | AS IS - NO IMPLICIT OR EXPLICIT warranty This may break your computer, it didn't break mine. It runs in User Mode which means it's less likely to cause system instability like the Blue Screen of Death.
4 | Check out the latest release to download, or find other versions below:
5 | # Newer Versions
6 | # Fork that is easy to install
7 | https://github.com/ge9/IddSampleDriver
8 |
9 | ## Fork with HDR
10 | https://github.com/itsmikethetech/Virtual-Display-Driver
11 |
12 | If you want me to build on this donate eth or similar here: 0xB01b6328F8Be53c852a54432bbEe630cE0Bd559a
13 | I now have a NEAR address: moopaloo.near
14 |
15 | Thanks to https://github.com/akatrevorjay/edid-generator for the hi-res EDID.
16 |
17 | # Indirect Display Driver Sample #
18 |
19 | This is a sample driver that shows how to create a Windows Indirect Display Driver using the IddCx class extension driver.
20 |
21 | ## Installation
22 |
23 | ### Scoop (recommended)
24 | If you have [Scoop](https://scoop.sh/), you can easily install this driver in one go. In an elevated prompt, run:
25 | ```powershell
26 | scoop bucket add extras
27 | scoop bucket add nonportable
28 | scoop install iddsampledriver-ge9-np -g
29 | ```
30 | The driver should be automatically installed and should be working out of the box.
31 |
32 | ### Manually
33 |
34 | 1. Download the latest version from the [releases](https://github.com/ge9/IddSampleDriver/releases/latest) page, and extract the contents to a folder.
35 | 2. Copy `option.txt` to `C:\IddSampleDriver\option.txt` before installing the driver **(important!)**.
36 | 3. See the [guide](https://github.com/roshkins/IddSampleDriver/releases) in [roshkins repo](https://github.com/roshkins/IddSampleDriver) for the rest of the installation steps.
37 |
38 | ## Configuration
39 | Configure `C:\IddSampleDriver\option.txt` to set the number of monitors and resolutions.
40 | See `option.txt`
41 |
42 |
43 | ## Background reading ##
44 |
45 | Start at the [Indirect Display Driver Model Overview](https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx) on MSDN.
46 |
47 | ## Customizing the sample ##
48 |
49 | The sample driver code is very simplistic and does nothing more than enumerate a single monitor when its device enters the D0/started power state. Throughout the code, there are `TODO` blocks with important information on implementing functionality in a production driver.
50 |
51 | ### Code structure ###
52 |
53 | * `Direct3DDevice` class
54 | * Contains logic for enumerating the correct render GPU from DXGI and creating a D3D device.
55 | * Manages the lifetime of a DXGI factory and a D3D device created for the render GPU the system is using to render frames for your indirect display device's swap-chain.
56 | * `SwapChainProcessor` class
57 | * Processes frames for a swap-chain assigned to the monitor object on a dedicated thread.
58 | * The sample code does nothing with the frames, but demonstrates a correct processing loop with error handling and notifying the OS of frame completion.
59 | * `IndirectDeviceContext` class
60 | * Processes device callbacks from IddCx.
61 | * Manages the creation and arrival of the sample monitor.
62 | * Handles swap-chain arrival and departure by creating a `Direct3DDevice` and handing it off to a `SwapChainProcessor`.
63 |
64 | ### First steps ###
65 |
66 | Consider the capabilities of your device. If the device supports multiple monitors being hotplugged and removed at runtime, you may want to abstract the monitors further from the `IndirectDeviceContext` class.
67 |
68 | The INF file included in the sample needs updating for production use. One field, `DeviceGroupId`, controls how the UMDF driver gets pooled with other UMDF drivers in the same process. Since indirect display drivers tend to be more complicated than other driver classes, it's highly recommended that you pick a unique string for this field which will cause instances of your device driver to pool in a dedicated process. This will improve system reliability in case your driver encounters a problem since other drivers will not be affected.
69 |
70 | Ensure the device information reported to `IddCxAdapterInitAsync` is accurate. This information determines how the device is reported to the OS and what static features (like support for gamma tables) the device will have available. If some information cannot be known immediately in the `EvtDeviceD0Entry` callback, IddCx allows the driver to call `IddCxAdapterInitAsync` at any point after D0 entry, before D0 exit.
71 |
72 | Careful attention should be paid to the frame processing loop. This will directly impact the performance of the user's system, so making use of the [Multimedia Class Scheduler Service](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684247(v=vs.85).aspx) and DXGI's support for [GPU prioritization](https://msdn.microsoft.com/en-us/library/windows/desktop/bb174534(v=vs.85).aspx) should be considered. Any significant work should be performed outside the main processing loop, such as by queuing work in a thread pool. See `SwapChainProcessor::RunCore` for more information.
73 |
74 | ## License
75 |
76 | License MIT and CC0 or Public Domain (for changes I made, check with Microsoft for their license), whichever is least restrictive -- Use it
77 |
78 | AS IS - NO IMPLICIT OR EXPLICIT warranty This may break your computer, it didn't break mine. It runs in User Mode which means it's less likely to cause system instability like the Blue Screen of Death.
79 |
80 | ## Acknowledgements
81 |
82 | See the original repo below:
83 | https://github.com/roshkins/IddSampleDriver
84 |
85 | Thanks to https://github.com/akatrevorjay/edid-generator for the hi-res EDID.
86 |
--------------------------------------------------------------------------------
/IddSampleDriver/IddSampleDriver.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 | Debug
22 | ARM
23 |
24 |
25 | Release
26 | ARM
27 |
28 |
29 | Debug
30 | ARM64
31 |
32 |
33 | Release
34 | ARM64
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}
49 | {32909489-7be5-497b-aafa-db6669d9b44b}
50 | v4.5
51 | 12.0
52 | Debug
53 | Win32
54 | IddSampleDriver
55 |
56 |
57 | WindowsUserModeDriver10.0
58 | DynamicLibrary
59 | Universal
60 |
61 |
62 | WindowsUserModeDriver10.0
63 | DynamicLibrary
64 | Universal
65 |
66 |
67 | WindowsUserModeDriver10.0
68 | DynamicLibrary
69 | Universal
70 |
71 |
72 | WindowsUserModeDriver10.0
73 | DynamicLibrary
74 | Universal
75 |
76 |
77 | WindowsUserModeDriver10.0
78 | DynamicLibrary
79 | Universal
80 |
81 |
82 | WindowsUserModeDriver10.0
83 | DynamicLibrary
84 | Universal
85 |
86 |
87 | WindowsUserModeDriver10.0
88 | DynamicLibrary
89 | Universal
90 |
91 |
92 | WindowsUserModeDriver10.0
93 | DynamicLibrary
94 | Universal
95 |
96 |
97 |
98 | Windows10
99 | true
100 | 2
101 | true
102 | 1
103 | 0
104 |
105 |
106 | Windows10
107 | false
108 | 2
109 | true
110 | 1
111 | 0
112 |
113 |
114 | Windows10
115 | true
116 | 2
117 | true
118 | 1
119 | 0
120 | Spectre
121 |
122 |
123 | Windows10
124 | false
125 | 2
126 | true
127 | 1
128 | 0
129 |
130 |
131 | Windows10
132 | true
133 | 2
134 | true
135 | 1
136 | 0
137 |
138 |
139 | Windows10
140 | false
141 | 2
142 | true
143 | 1
144 | 0
145 |
146 |
147 | Windows10
148 | true
149 | 2
150 | true
151 | 1
152 | 0
153 |
154 |
155 | Windows10
156 | false
157 | 2
158 | true
159 | 1
160 | 0
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | DbgengRemoteDebugger
171 | true
172 |
173 |
174 | DbgengRemoteDebugger
175 | true
176 |
177 |
178 | DbgengRemoteDebugger
179 | true
180 | true
181 |
182 |
183 | DbgengRemoteDebugger
184 | true
185 | true
186 |
187 |
188 | DbgengRemoteDebugger
189 | true
190 |
191 |
192 | DbgengRemoteDebugger
193 | true
194 |
195 |
196 | DbgengRemoteDebugger
197 | true
198 |
199 |
200 | DbgengRemoteDebugger
201 | true
202 |
203 |
204 |
205 | true
206 | true
207 | trace.h
208 | Async
209 | true
210 |
211 |
212 | %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib
213 |
214 |
215 |
216 |
217 | true
218 | true
219 | trace.h
220 | Async
221 | true
222 |
223 |
224 | %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib
225 |
226 |
227 |
228 |
229 | true
230 | true
231 | trace.h
232 | Async
233 | true
234 |
235 |
236 | %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib
237 |
238 |
239 |
240 |
241 | true
242 | true
243 | trace.h
244 | Async
245 | true
246 |
247 |
248 | %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib
249 |
250 |
251 | SHA256
252 |
253 |
254 |
255 |
256 | true
257 | true
258 | trace.h
259 | Async
260 | true
261 |
262 |
263 | %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib
264 |
265 |
266 |
267 |
268 | true
269 | true
270 | trace.h
271 | Async
272 | true
273 |
274 |
275 | %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib
276 |
277 |
278 |
279 |
280 | true
281 | true
282 | trace.h
283 | Async
284 | true
285 |
286 |
287 | %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib
288 |
289 |
290 |
291 |
292 | true
293 | true
294 | trace.h
295 | Async
296 | true
297 |
298 |
299 | %(AdditionalDependencies);OneCoreUAP.lib;avrt.lib
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
--------------------------------------------------------------------------------
/IddSampleDriver/Driver.cpp:
--------------------------------------------------------------------------------
1 | /*++
2 |
3 | Copyright (c) Microsoft Corporation
4 |
5 | Abstract:
6 |
7 | This module contains a sample implementation of an indirect display driver. See the included README.md file and the
8 | various TODO blocks throughout this file and all accompanying files for information on building a production driver.
9 |
10 | MSDN documentation on indirect displays can be found at https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx.
11 |
12 | Environment:
13 |
14 | User Mode, UMDF
15 |
16 | --*/
17 |
18 | #include "Driver.h"
19 | #include "Driver.tmh"
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | using namespace std;
27 | using namespace Microsoft::IndirectDisp;
28 | using namespace Microsoft::WRL;
29 |
30 | extern "C" DRIVER_INITIALIZE DriverEntry;
31 |
32 | EVT_WDF_DRIVER_DEVICE_ADD IddSampleDeviceAdd;
33 | EVT_WDF_DEVICE_D0_ENTRY IddSampleDeviceD0Entry;
34 |
35 | EVT_IDD_CX_ADAPTER_INIT_FINISHED IddSampleAdapterInitFinished;
36 | EVT_IDD_CX_ADAPTER_COMMIT_MODES IddSampleAdapterCommitModes;
37 |
38 | EVT_IDD_CX_PARSE_MONITOR_DESCRIPTION IddSampleParseMonitorDescription;
39 | EVT_IDD_CX_MONITOR_GET_DEFAULT_DESCRIPTION_MODES IddSampleMonitorGetDefaultModes;
40 | EVT_IDD_CX_MONITOR_QUERY_TARGET_MODES IddSampleMonitorQueryModes;
41 |
42 | EVT_IDD_CX_MONITOR_ASSIGN_SWAPCHAIN IddSampleMonitorAssignSwapChain;
43 | EVT_IDD_CX_MONITOR_UNASSIGN_SWAPCHAIN IddSampleMonitorUnassignSwapChain;
44 |
45 | vector> monitorModes;
46 | vector< DISPLAYCONFIG_VIDEO_SIGNAL_INFO> s_KnownMonitorModes2;
47 | UINT numVirtualDisplays;
48 |
49 | struct IndirectDeviceContextWrapper
50 | {
51 | IndirectDeviceContext* pContext;
52 |
53 | void Cleanup()
54 | {
55 | delete pContext;
56 | pContext = nullptr;
57 | }
58 | };
59 |
60 | // This macro creates the methods for accessing an IndirectDeviceContextWrapper as a context for a WDF object
61 | WDF_DECLARE_CONTEXT_TYPE(IndirectDeviceContextWrapper);
62 |
63 | extern "C" BOOL WINAPI DllMain(
64 | _In_ HINSTANCE hInstance,
65 | _In_ UINT dwReason,
66 | _In_opt_ LPVOID lpReserved)
67 | {
68 | UNREFERENCED_PARAMETER(hInstance);
69 | UNREFERENCED_PARAMETER(lpReserved);
70 | UNREFERENCED_PARAMETER(dwReason);
71 |
72 | return TRUE;
73 | }
74 |
75 | _Use_decl_annotations_
76 | extern "C" NTSTATUS DriverEntry(
77 | PDRIVER_OBJECT pDriverObject,
78 | PUNICODE_STRING pRegistryPath
79 | )
80 | {
81 | WDF_DRIVER_CONFIG Config;
82 | NTSTATUS Status;
83 |
84 | WDF_OBJECT_ATTRIBUTES Attributes;
85 | WDF_OBJECT_ATTRIBUTES_INIT(&Attributes);
86 |
87 | WDF_DRIVER_CONFIG_INIT(&Config,
88 | IddSampleDeviceAdd
89 | );
90 |
91 | Status = WdfDriverCreate(pDriverObject, pRegistryPath, &Attributes, &Config, WDF_NO_HANDLE);
92 | if (!NT_SUCCESS(Status))
93 | {
94 | return Status;
95 | }
96 |
97 | return Status;
98 | }
99 | vector split(string& input, char delimiter)
100 | {
101 | istringstream stream(input);
102 | string field;
103 | vector result;
104 | while (getline(stream, field, delimiter)) {
105 | result.push_back(field);
106 | }
107 | return result;
108 | }
109 |
110 | void loadOptions(string filepath) {
111 | ifstream ifs(filepath);
112 |
113 | string line;
114 | vector> res;
115 | getline(ifs, line);//num of displays
116 | numVirtualDisplays = stoi(line);
117 | while (getline(ifs, line)) {
118 | vector strvec = split(line, ',');
119 | if (strvec.size() == 3 && strvec[0].substr(0, 1) != "#") {
120 | res.push_back({ stoi(strvec[0]),stoi(strvec[1]),stoi(strvec[2]) });
121 | }
122 | }
123 | monitorModes = res; return;
124 | }
125 | _Use_decl_annotations_
126 | NTSTATUS IddSampleDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT pDeviceInit)
127 | {
128 | NTSTATUS Status = STATUS_SUCCESS;
129 | WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks;
130 |
131 | UNREFERENCED_PARAMETER(Driver);
132 |
133 | // Register for power callbacks - in this sample only power-on is needed
134 | WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks);
135 | PnpPowerCallbacks.EvtDeviceD0Entry = IddSampleDeviceD0Entry;
136 | WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &PnpPowerCallbacks);
137 |
138 | IDD_CX_CLIENT_CONFIG IddConfig;
139 | IDD_CX_CLIENT_CONFIG_INIT(&IddConfig);
140 |
141 | // If the driver wishes to handle custom IoDeviceControl requests, it's necessary to use this callback since IddCx
142 | // redirects IoDeviceControl requests to an internal queue. This sample does not need this.
143 | // IddConfig.EvtIddCxDeviceIoControl = IddSampleIoDeviceControl;
144 | loadOptions("C:\\IddSampleDriver\\option.txt");
145 | IddConfig.EvtIddCxAdapterInitFinished = IddSampleAdapterInitFinished;
146 |
147 | IddConfig.EvtIddCxParseMonitorDescription = IddSampleParseMonitorDescription;
148 | IddConfig.EvtIddCxMonitorGetDefaultDescriptionModes = IddSampleMonitorGetDefaultModes;
149 | IddConfig.EvtIddCxMonitorQueryTargetModes = IddSampleMonitorQueryModes;
150 | IddConfig.EvtIddCxAdapterCommitModes = IddSampleAdapterCommitModes;
151 | IddConfig.EvtIddCxMonitorAssignSwapChain = IddSampleMonitorAssignSwapChain;
152 | IddConfig.EvtIddCxMonitorUnassignSwapChain = IddSampleMonitorUnassignSwapChain;
153 |
154 | Status = IddCxDeviceInitConfig(pDeviceInit, &IddConfig);
155 | if (!NT_SUCCESS(Status))
156 | {
157 | return Status;
158 | }
159 |
160 | WDF_OBJECT_ATTRIBUTES Attr;
161 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attr, IndirectDeviceContextWrapper);
162 | Attr.EvtCleanupCallback = [](WDFOBJECT Object)
163 | {
164 | // Automatically cleanup the context when the WDF object is about to be deleted
165 | auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(Object);
166 | if (pContext)
167 | {
168 | pContext->Cleanup();
169 | }
170 | };
171 |
172 | WDFDEVICE Device = nullptr;
173 | Status = WdfDeviceCreate(&pDeviceInit, &Attr, &Device);
174 | if (!NT_SUCCESS(Status))
175 | {
176 | return Status;
177 | }
178 |
179 | Status = IddCxDeviceInitialize(Device);
180 |
181 | // Create a new device context object and attach it to the WDF device object
182 | auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(Device);
183 | pContext->pContext = new IndirectDeviceContext(Device);
184 |
185 | return Status;
186 | }
187 |
188 | _Use_decl_annotations_
189 | NTSTATUS IddSampleDeviceD0Entry(WDFDEVICE Device, WDF_POWER_DEVICE_STATE PreviousState)
190 | {
191 | UNREFERENCED_PARAMETER(PreviousState);
192 |
193 | // This function is called by WDF to start the device in the fully-on power state.
194 |
195 | auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(Device);
196 | pContext->pContext->InitAdapter();
197 |
198 | return STATUS_SUCCESS;
199 | }
200 |
201 | #pragma region Direct3DDevice
202 |
203 | Direct3DDevice::Direct3DDevice(LUID AdapterLuid) : AdapterLuid(AdapterLuid)
204 | {
205 |
206 | }
207 |
208 | Direct3DDevice::Direct3DDevice()
209 | {
210 |
211 | }
212 |
213 | HRESULT Direct3DDevice::Init()
214 | {
215 | // The DXGI factory could be cached, but if a new render adapter appears on the system, a new factory needs to be
216 | // created. If caching is desired, check DxgiFactory->IsCurrent() each time and recreate the factory if !IsCurrent.
217 | HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&DxgiFactory));
218 | if (FAILED(hr))
219 | {
220 | return hr;
221 | }
222 |
223 | // Find the specified render adapter
224 | hr = DxgiFactory->EnumAdapterByLuid(AdapterLuid, IID_PPV_ARGS(&Adapter));
225 | if (FAILED(hr))
226 | {
227 | return hr;
228 | }
229 |
230 | // Create a D3D device using the render adapter. BGRA support is required by the WHQL test suite.
231 | hr = D3D11CreateDevice(Adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, nullptr, 0, D3D11_SDK_VERSION, &Device, nullptr, &DeviceContext);
232 | if (FAILED(hr))
233 | {
234 | // If creating the D3D device failed, it's possible the render GPU was lost (e.g. detachable GPU) or else the
235 | // system is in a transient state.
236 | return hr;
237 | }
238 |
239 | return S_OK;
240 | }
241 |
242 | #pragma endregion
243 |
244 | #pragma region SwapChainProcessor
245 |
246 | SwapChainProcessor::SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, shared_ptr Device, HANDLE NewFrameEvent)
247 | : m_hSwapChain(hSwapChain), m_Device(Device), m_hAvailableBufferEvent(NewFrameEvent)
248 | {
249 | m_hTerminateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
250 |
251 | // Immediately create and run the swap-chain processing thread, passing 'this' as the thread parameter
252 | m_hThread.Attach(CreateThread(nullptr, 0, RunThread, this, 0, nullptr));
253 | }
254 |
255 | SwapChainProcessor::~SwapChainProcessor()
256 | {
257 | // Alert the swap-chain processing thread to terminate
258 | SetEvent(m_hTerminateEvent.Get());
259 |
260 | if (m_hThread.Get())
261 | {
262 | // Wait for the thread to terminate
263 | WaitForSingleObject(m_hThread.Get(), INFINITE);
264 | }
265 | }
266 |
267 | DWORD CALLBACK SwapChainProcessor::RunThread(LPVOID Argument)
268 | {
269 | reinterpret_cast(Argument)->Run();
270 | return 0;
271 | }
272 |
273 | void SwapChainProcessor::Run()
274 | {
275 | // For improved performance, make use of the Multimedia Class Scheduler Service, which will intelligently
276 | // prioritize this thread for improved throughput in high CPU-load scenarios.
277 | DWORD AvTask = 0;
278 | HANDLE AvTaskHandle = AvSetMmThreadCharacteristicsW(L"Distribution", &AvTask);
279 |
280 | RunCore();
281 |
282 | // Always delete the swap-chain object when swap-chain processing loop terminates in order to kick the system to
283 | // provide a new swap-chain if necessary.
284 | WdfObjectDelete((WDFOBJECT)m_hSwapChain);
285 | m_hSwapChain = nullptr;
286 |
287 | AvRevertMmThreadCharacteristics(AvTaskHandle);
288 | }
289 |
290 | void SwapChainProcessor::RunCore()
291 | {
292 | // Get the DXGI device interface
293 | ComPtr DxgiDevice;
294 | HRESULT hr = m_Device->Device.As(&DxgiDevice);
295 | if (FAILED(hr))
296 | {
297 | return;
298 | }
299 |
300 | IDARG_IN_SWAPCHAINSETDEVICE SetDevice = {};
301 | SetDevice.pDevice = DxgiDevice.Get();
302 |
303 | hr = IddCxSwapChainSetDevice(m_hSwapChain, &SetDevice);
304 | if (FAILED(hr))
305 | {
306 | return;
307 | }
308 |
309 | // Acquire and release buffers in a loop
310 | for (;;)
311 | {
312 | ComPtr AcquiredBuffer;
313 |
314 | // Ask for the next buffer from the producer
315 | IDARG_OUT_RELEASEANDACQUIREBUFFER Buffer = {};
316 | hr = IddCxSwapChainReleaseAndAcquireBuffer(m_hSwapChain, &Buffer);
317 |
318 | // AcquireBuffer immediately returns STATUS_PENDING if no buffer is yet available
319 | if (hr == E_PENDING)
320 | {
321 | // We must wait for a new buffer
322 | HANDLE WaitHandles[] =
323 | {
324 | m_hAvailableBufferEvent,
325 | m_hTerminateEvent.Get()
326 | };
327 | DWORD WaitResult = WaitForMultipleObjects(ARRAYSIZE(WaitHandles), WaitHandles, FALSE, 16);
328 | if (WaitResult == WAIT_OBJECT_0 || WaitResult == WAIT_TIMEOUT)
329 | {
330 | // We have a new buffer, so try the AcquireBuffer again
331 | continue;
332 | }
333 | else if (WaitResult == WAIT_OBJECT_0 + 1)
334 | {
335 | // We need to terminate
336 | break;
337 | }
338 | else
339 | {
340 | // The wait was cancelled or something unexpected happened
341 | hr = HRESULT_FROM_WIN32(WaitResult);
342 | break;
343 | }
344 | }
345 | else if (SUCCEEDED(hr))
346 | {
347 | AcquiredBuffer.Attach(Buffer.MetaData.pSurface);
348 |
349 | // ==============================
350 | // TODO: Process the frame here
351 | //
352 | // This is the most performance-critical section of code in an IddCx driver. It's important that whatever
353 | // is done with the acquired surface be finished as quickly as possible. This operation could be:
354 | // * a GPU copy to another buffer surface for later processing (such as a staging surface for mapping to CPU memory)
355 | // * a GPU encode operation
356 | // * a GPU VPBlt to another surface
357 | // * a GPU custom compute shader encode operation
358 | // ==============================
359 |
360 | AcquiredBuffer.Reset();
361 | hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain);
362 | if (FAILED(hr))
363 | {
364 | break;
365 | }
366 |
367 | // ==============================
368 | // TODO: Report frame statistics once the asynchronous encode/send work is completed
369 | //
370 | // Drivers should report information about sub-frame timings, like encode time, send time, etc.
371 | // ==============================
372 | // IddCxSwapChainReportFrameStatistics(m_hSwapChain, ...);
373 | }
374 | else
375 | {
376 | // The swap-chain was likely abandoned (e.g. DXGI_ERROR_ACCESS_LOST), so exit the processing loop
377 | break;
378 | }
379 | }
380 | }
381 |
382 | #pragma endregion
383 |
384 | #pragma region IndirectDeviceContext
385 |
386 | const UINT64 MHZ = 1000000;
387 | const UINT64 KHZ = 1000;
388 |
389 | constexpr DISPLAYCONFIG_VIDEO_SIGNAL_INFO dispinfo(UINT32 h, UINT32 v, UINT32 r) {
390 | const UINT32 clock_rate = r * (v + 4) * (v + 4) + 1000;
391 | return {
392 | clock_rate, // pixel clock rate [Hz]
393 | { clock_rate, v + 4 }, // fractional horizontal refresh rate [Hz]
394 | { clock_rate, (v + 4) * (v + 4) }, // fractional vertical refresh rate [Hz]
395 | { h, v }, // (horizontal, vertical) active pixel resolution
396 | { h + 4, v + 4 }, // (horizontal, vertical) total pixel resolution
397 | { { 255, 0 }}, // video standard and vsync divider
398 | DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE
399 | };
400 | }
401 |
402 | // This is a sample monitor EDID - FOR SAMPLE PURPOSES ONLY
403 | const BYTE IndirectDeviceContext::s_KnownMonitorEdid[] =
404 | {
405 | /* 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x79,0x5E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA6,0x01,0x03,0x80,0x28,
406 | 0x1E,0x78,0x0A,0xEE,0x91,0xA3,0x54,0x4C,0x99,0x26,0x0F,0x50,0x54,0x20,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,
407 | 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xA0,0x0F,0x20,0x00,0x31,0x58,0x1C,0x20,0x28,0x80,0x14,0x00,
408 | 0x90,0x2C,0x11,0x00,0x00,0x1E,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
409 | 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
410 | 0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6E */
411 |
412 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x31, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
413 | 0x05, 0x16, 0x01, 0x03, 0x6D, 0x32, 0x1C, 0x78, 0xEA, 0x5E, 0xC0, 0xA4, 0x59, 0x4A, 0x98, 0x25,
414 | 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xD1, 0xC0, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
415 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
416 | 0x45, 0x00, 0xF4, 0x19, 0x11, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x4C, 0x69, 0x6E,
417 | 0x75, 0x78, 0x20, 0x23, 0x30, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x3B,
418 | 0x3D, 0x42, 0x44, 0x0F, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC,
419 | 0x00, 0x4C, 0x69, 0x6E, 0x75, 0x78, 0x20, 0x46, 0x48, 0x44, 0x0A, 0x20, 0x20, 0x20, 0x00, 0x05
420 |
421 | };
422 |
423 | IndirectDeviceContext::IndirectDeviceContext(_In_ WDFDEVICE WdfDevice) :
424 | m_WdfDevice(WdfDevice)
425 | {
426 | }
427 |
428 | IndirectDeviceContext::~IndirectDeviceContext()
429 | {
430 | m_ProcessingThread.reset();
431 | }
432 |
433 | #define NUM_VIRTUAL_DISPLAYS 1
434 |
435 | void IndirectDeviceContext::InitAdapter()
436 | {
437 | // ==============================
438 | // TODO: Update the below diagnostic information in accordance with the target hardware. The strings and version
439 | // numbers are used for telemetry and may be displayed to the user in some situations.
440 | //
441 | // This is also where static per-adapter capabilities are determined.
442 | // ==============================
443 |
444 | IDDCX_ADAPTER_CAPS AdapterCaps = {};
445 | AdapterCaps.Size = sizeof(AdapterCaps);
446 |
447 | // Declare basic feature support for the adapter (required)
448 | AdapterCaps.MaxMonitorsSupported = numVirtualDisplays;
449 | AdapterCaps.EndPointDiagnostics.Size = sizeof(AdapterCaps.EndPointDiagnostics);
450 | AdapterCaps.EndPointDiagnostics.GammaSupport = IDDCX_FEATURE_IMPLEMENTATION_NONE;
451 | AdapterCaps.EndPointDiagnostics.TransmissionType = IDDCX_TRANSMISSION_TYPE_WIRED_OTHER;
452 |
453 | // Declare your device strings for telemetry (required)
454 | AdapterCaps.EndPointDiagnostics.pEndPointFriendlyName = L"IddSample Device";
455 | AdapterCaps.EndPointDiagnostics.pEndPointManufacturerName = L"Microsoft";
456 | AdapterCaps.EndPointDiagnostics.pEndPointModelName = L"IddSample Model";
457 |
458 | // Declare your hardware and firmware versions (required)
459 | IDDCX_ENDPOINT_VERSION Version = {};
460 | Version.Size = sizeof(Version);
461 | Version.MajorVer = 1;
462 | AdapterCaps.EndPointDiagnostics.pFirmwareVersion = &Version;
463 | AdapterCaps.EndPointDiagnostics.pHardwareVersion = &Version;
464 |
465 | // Initialize a WDF context that can store a pointer to the device context object
466 | WDF_OBJECT_ATTRIBUTES Attr;
467 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attr, IndirectDeviceContextWrapper);
468 |
469 | IDARG_IN_ADAPTER_INIT AdapterInit = {};
470 | AdapterInit.WdfDevice = m_WdfDevice;
471 | AdapterInit.pCaps = &AdapterCaps;
472 | AdapterInit.ObjectAttributes = &Attr;
473 |
474 | // Start the initialization of the adapter, which will trigger the AdapterFinishInit callback later
475 | IDARG_OUT_ADAPTER_INIT AdapterInitOut;
476 | NTSTATUS Status = IddCxAdapterInitAsync(&AdapterInit, &AdapterInitOut);
477 |
478 | if (NT_SUCCESS(Status))
479 | {
480 | // Store a reference to the WDF adapter handle
481 | m_Adapter = AdapterInitOut.AdapterObject;
482 |
483 | // Store the device context object into the WDF object context
484 | auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(AdapterInitOut.AdapterObject);
485 | pContext->pContext = this;
486 | }
487 | }
488 |
489 | void IndirectDeviceContext::FinishInit()
490 | {
491 | for (unsigned int i = 0; i < numVirtualDisplays; i++) {
492 | CreateMonitor(i);
493 | }
494 | }
495 |
496 | void IndirectDeviceContext::CreateMonitor(unsigned int index) {
497 | // ==============================
498 | // TODO: In a real driver, the EDID should be retrieved dynamically from a connected physical monitor. The EDID
499 | // provided here is purely for demonstration, as it describes only 640x480 @ 60 Hz and 800x600 @ 60 Hz. Monitor
500 | // manufacturers are required to correctly fill in physical monitor attributes in order to allow the OS to optimize
501 | // settings like viewing distance and scale factor. Manufacturers should also use a unique serial number every
502 | // single device to ensure the OS can tell the monitors apart.
503 | // ==============================
504 |
505 | WDF_OBJECT_ATTRIBUTES Attr;
506 | WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attr, IndirectDeviceContextWrapper);
507 |
508 | IDDCX_MONITOR_INFO MonitorInfo = {};
509 | MonitorInfo.Size = sizeof(MonitorInfo);
510 | MonitorInfo.MonitorType = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI;
511 | MonitorInfo.ConnectorIndex = index;
512 | MonitorInfo.MonitorDescription.Size = sizeof(MonitorInfo.MonitorDescription);
513 | MonitorInfo.MonitorDescription.Type = IDDCX_MONITOR_DESCRIPTION_TYPE_EDID;
514 | MonitorInfo.MonitorDescription.DataSize = sizeof(s_KnownMonitorEdid);
515 | MonitorInfo.MonitorDescription.pData = const_cast(s_KnownMonitorEdid);
516 |
517 | // ==============================
518 | // TODO: The monitor's container ID should be distinct from "this" device's container ID if the monitor is not
519 | // permanently attached to the display adapter device object. The container ID is typically made unique for each
520 | // monitor and can be used to associate the monitor with other devices, like audio or input devices. In this
521 | // sample we generate a random container ID GUID, but it's best practice to choose a stable container ID for a
522 | // unique monitor or to use "this" device's container ID for a permanent/integrated monitor.
523 | // ==============================
524 |
525 | // Create a container ID
526 | CoCreateGuid(&MonitorInfo.MonitorContainerId);
527 |
528 | IDARG_IN_MONITORCREATE MonitorCreate = {};
529 | MonitorCreate.ObjectAttributes = &Attr;
530 | MonitorCreate.pMonitorInfo = &MonitorInfo;
531 |
532 | // Create a monitor object with the specified monitor descriptor
533 | IDARG_OUT_MONITORCREATE MonitorCreateOut;
534 | NTSTATUS Status = IddCxMonitorCreate(m_Adapter, &MonitorCreate, &MonitorCreateOut);
535 | if (NT_SUCCESS(Status))
536 | {
537 | m_Monitor = MonitorCreateOut.MonitorObject;
538 |
539 | // Associate the monitor with this device context
540 | auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(MonitorCreateOut.MonitorObject);
541 | pContext->pContext = this;
542 |
543 | // Tell the OS that the monitor has been plugged in
544 | IDARG_OUT_MONITORARRIVAL ArrivalOut;
545 | Status = IddCxMonitorArrival(m_Monitor, &ArrivalOut);
546 | }
547 | }
548 |
549 | void IndirectDeviceContext::AssignSwapChain(IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent)
550 | {
551 | m_ProcessingThread.reset();
552 |
553 | auto Device = make_shared(RenderAdapter);
554 | if (FAILED(Device->Init()))
555 | {
556 | // It's important to delete the swap-chain if D3D initialization fails, so that the OS knows to generate a new
557 | // swap-chain and try again.
558 | WdfObjectDelete(SwapChain);
559 | }
560 | else
561 | {
562 | // Create a new swap-chain processing thread
563 | m_ProcessingThread.reset(new SwapChainProcessor(SwapChain, Device, NewFrameEvent));
564 | }
565 | }
566 |
567 | void IndirectDeviceContext::UnassignSwapChain()
568 | {
569 | // Stop processing the last swap-chain
570 | m_ProcessingThread.reset();
571 | }
572 |
573 | #pragma endregion
574 |
575 | #pragma region DDI Callbacks
576 |
577 | _Use_decl_annotations_
578 | NTSTATUS IddSampleAdapterInitFinished(IDDCX_ADAPTER AdapterObject, const IDARG_IN_ADAPTER_INIT_FINISHED* pInArgs)
579 | {
580 | // This is called when the OS has finished setting up the adapter for use by the IddCx driver. It's now possible
581 | // to report attached monitors.
582 |
583 | auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(AdapterObject);
584 | if (NT_SUCCESS(pInArgs->AdapterInitStatus))
585 | {
586 | pContext->pContext->FinishInit();
587 | }
588 |
589 | return STATUS_SUCCESS;
590 | }
591 |
592 | _Use_decl_annotations_
593 | NTSTATUS IddSampleAdapterCommitModes(IDDCX_ADAPTER AdapterObject, const IDARG_IN_COMMITMODES* pInArgs)
594 | {
595 | UNREFERENCED_PARAMETER(AdapterObject);
596 | UNREFERENCED_PARAMETER(pInArgs);
597 |
598 | // For the sample, do nothing when modes are picked - the swap-chain is taken care of by IddCx
599 |
600 | // ==============================
601 | // TODO: In a real driver, this function would be used to reconfigure the device to commit the new modes. Loop
602 | // through pInArgs->pPaths and look for IDDCX_PATH_FLAGS_ACTIVE. Any path not active is inactive (e.g. the monitor
603 | // should be turned off).
604 | // ==============================
605 |
606 | return STATUS_SUCCESS;
607 | }
608 | _Use_decl_annotations_
609 | NTSTATUS IddSampleParseMonitorDescription(const IDARG_IN_PARSEMONITORDESCRIPTION* pInArgs, IDARG_OUT_PARSEMONITORDESCRIPTION* pOutArgs)
610 | {
611 | // ==============================
612 | // TODO: In a real driver, this function would be called to generate monitor modes for an EDID by parsing it. In
613 | // this sample driver, we hard-code the EDID, so this function can generate known modes.
614 | // ==============================
615 |
616 | for (int i = 0; i < monitorModes.size(); i++) {
617 | s_KnownMonitorModes2.push_back(dispinfo(std::get<0>(monitorModes[i]), std::get<1>(monitorModes[i]), std::get<2>(monitorModes[i])));
618 | }
619 | pOutArgs->MonitorModeBufferOutputCount = (UINT)monitorModes.size();
620 |
621 | if (pInArgs->MonitorModeBufferInputCount < monitorModes.size())
622 | {
623 | // Return success if there was no buffer, since the caller was only asking for a count of modes
624 | return (pInArgs->MonitorModeBufferInputCount > 0) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS;
625 | }
626 | else
627 | {
628 | // Copy the known modes to the output buffer
629 | for (DWORD ModeIndex = 0; ModeIndex < monitorModes.size(); ModeIndex++)
630 | {
631 | pInArgs->pMonitorModes[ModeIndex].Size = sizeof(IDDCX_MONITOR_MODE);
632 | pInArgs->pMonitorModes[ModeIndex].Origin = IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR;
633 | pInArgs->pMonitorModes[ModeIndex].MonitorVideoSignalInfo = s_KnownMonitorModes2[ModeIndex];
634 | }
635 |
636 | // Set the preferred mode as represented in the EDID
637 | pOutArgs->PreferredMonitorModeIdx = 0;
638 |
639 | return STATUS_SUCCESS;
640 | }
641 | }
642 |
643 | _Use_decl_annotations_
644 | NTSTATUS IddSampleMonitorGetDefaultModes(IDDCX_MONITOR MonitorObject, const IDARG_IN_GETDEFAULTDESCRIPTIONMODES* pInArgs, IDARG_OUT_GETDEFAULTDESCRIPTIONMODES* pOutArgs)
645 | {
646 | UNREFERENCED_PARAMETER(MonitorObject);
647 | UNREFERENCED_PARAMETER(pInArgs);
648 | UNREFERENCED_PARAMETER(pOutArgs);
649 |
650 | // Should never be called since we create a single monitor with a known EDID in this sample driver.
651 |
652 | // ==============================
653 | // TODO: In a real driver, this function would be called to generate monitor modes for a monitor with no EDID.
654 | // Drivers should report modes that are guaranteed to be supported by the transport protocol and by nearly all
655 | // monitors (such 640x480, 800x600, or 1024x768). If the driver has access to monitor modes from a descriptor other
656 | // than an EDID, those modes would also be reported here.
657 | // ==============================
658 |
659 | return STATUS_NOT_IMPLEMENTED;
660 | }
661 |
662 | ///
663 | /// Creates a target mode from the fundamental mode attributes.
664 | ///
665 | void CreateTargetMode(DISPLAYCONFIG_VIDEO_SIGNAL_INFO& Mode, UINT Width, UINT Height, UINT VSync)
666 | {
667 | Mode.totalSize.cx = Mode.activeSize.cx = Width;
668 | Mode.totalSize.cy = Mode.activeSize.cy = Height;
669 | Mode.AdditionalSignalInfo.vSyncFreqDivider = 1;
670 | Mode.AdditionalSignalInfo.videoStandard = 255;
671 | Mode.vSyncFreq.Numerator = VSync;
672 | Mode.vSyncFreq.Denominator = Mode.hSyncFreq.Denominator = 1;
673 | Mode.hSyncFreq.Numerator = VSync * Height;
674 | Mode.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
675 | Mode.pixelRate = VSync * Width * Height;
676 | }
677 |
678 | void CreateTargetMode(IDDCX_TARGET_MODE& Mode, UINT Width, UINT Height, UINT VSync)
679 | {
680 | Mode.Size = sizeof(Mode);
681 | CreateTargetMode(Mode.TargetVideoSignalInfo.targetVideoSignalInfo, Width, Height, VSync);
682 | }
683 |
684 | _Use_decl_annotations_
685 | NTSTATUS IddSampleMonitorQueryModes(IDDCX_MONITOR MonitorObject, const IDARG_IN_QUERYTARGETMODES* pInArgs, IDARG_OUT_QUERYTARGETMODES* pOutArgs)////////////////////////////////////////////////////////////////////////////////
686 | {
687 | UNREFERENCED_PARAMETER(MonitorObject);
688 |
689 | vector TargetModes(monitorModes.size());
690 |
691 | // Create a set of modes supported for frame processing and scan-out. These are typically not based on the
692 | // monitor's descriptor and instead are based on the static processing capability of the device. The OS will
693 | // report the available set of modes for a given output as the intersection of monitor modes with target modes.
694 |
695 | for (int i = 0; i < monitorModes.size(); i++) {
696 | CreateTargetMode(TargetModes[i], std::get<0>(monitorModes[i]), std::get<1>(monitorModes[i]), std::get<2>(monitorModes[i]));
697 | }
698 |
699 | pOutArgs->TargetModeBufferOutputCount = (UINT)TargetModes.size();
700 |
701 | if (pInArgs->TargetModeBufferInputCount >= TargetModes.size())
702 | {
703 | copy(TargetModes.begin(), TargetModes.end(), pInArgs->pTargetModes);
704 | }
705 |
706 | return STATUS_SUCCESS;
707 | }
708 |
709 | _Use_decl_annotations_
710 | NTSTATUS IddSampleMonitorAssignSwapChain(IDDCX_MONITOR MonitorObject, const IDARG_IN_SETSWAPCHAIN* pInArgs)
711 | {
712 | auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(MonitorObject);
713 | pContext->pContext->AssignSwapChain(pInArgs->hSwapChain, pInArgs->RenderAdapterLuid, pInArgs->hNextSurfaceAvailable);
714 | return STATUS_SUCCESS;
715 | }
716 |
717 | _Use_decl_annotations_
718 | NTSTATUS IddSampleMonitorUnassignSwapChain(IDDCX_MONITOR MonitorObject)
719 | {
720 | auto* pContext = WdfObjectGet_IndirectDeviceContextWrapper(MonitorObject);
721 | pContext->pContext->UnassignSwapChain();
722 | return STATUS_SUCCESS;
723 | }
724 |
725 | #pragma endregion
726 |
--------------------------------------------------------------------------------