<p dir="ltr">Hi,</p>
<p dir="ltr">Can anyone review this patch so I can resend the patches after the rework?</p>
<div class="gmail_extra"><br><div class="gmail_quote">On 9 Aug 2016 3:08 p.m., "Sameeh Jubran" <<a href="mailto:sameeh@daynix.com">sameeh@daynix.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">The Direct3D 9 API operates on either the Windows XP display driver<br>
model (XPDM) or the Windows Vista display driver model (WDDM), depending<br>
on the operating system installed.<br>
<br>
This patch implements the WDDM interface while using the CCD API to do<br>
so. Moreover it introduces multiple monitors support and arbitrary<br>
resolution for Windows 10 while preserving backward compatiblity with previous<br>
versions of Windows.<br>
<br>
Based on a patch by Sandy Stutsman <<a href="mailto:sstutsma@redhat.com">sstutsma@redhat.com</a>><br>
<br>
Signed-off-by: Dmitry Fleytman <<a href="mailto:dfleytma@redhat.com">dfleytma@redhat.com</a>><br>
Signed-off-by: Sameeh Jubran <<a href="mailto:sameeh@daynix.com">sameeh@daynix.com</a>><br>
---<br>
 vdagent/display_configuration.<wbr>cpp | 355 ++++++++++++++++++++++++++++++<wbr>+++++++-<br>
 vdagent/display_configuration.<wbr>h   |  47 +++++<br>
 2 files changed, 401 insertions(+), 1 deletion(-)<br>
<br>
diff --git a/vdagent/display_<wbr>configuration.cpp b/vdagent/display_<wbr>configuration.cpp<br>
index 5e40d05..4db093f 100755<br>
--- a/vdagent/display_<wbr>configuration.cpp<br>
+++ b/vdagent/display_<wbr>configuration.cpp<br>
@@ -152,6 +152,54 @@ struct DISPLAYCONFIG_PATH_INFO {<br>
     UINT32 flags;<br>
 };<br>
<br>
+<br>
+enum D3DKMT_ESCAPETYPE {<br>
+    D3DKMT_ESCAPE_DRIVERPRIVATE = 0<br>
+};<br>
+<br>
+struct D3DDDI_ESCAPEFLAGS {<br>
+    union {<br>
+        struct {<br>
+            UINT    Reserved : 31;<br>
+        };<br>
+        UINT        Value;<br>
+    };<br>
+};<br>
+<br>
+struct D3DKMT_ESCAPE {<br>
+    D3D_HANDLE hAdapter;<br>
+    D3D_HANDLE hDevice;<br>
+    D3DKMT_ESCAPETYPE Type;<br>
+    D3DDDI_ESCAPEFLAGS Flags;<br>
+    VOID* pPrivateDriverData;<br>
+    UINT PrivateDriverDataSize;<br>
+    D3D_HANDLE hContext;<br>
+};<br>
+<br>
+struct D3DKMT_OPENADAPTERFROMHDC {<br>
+    HDC hDc;<br>
+    D3D_HANDLE hAdapter;<br>
+    LUID AdapterLuid;<br>
+    UINT VidPnSourceId;<br>
+};<br>
+<br>
+struct D3DKMT_CLOSEADAPTER {<br>
+    D3D_HANDLE hAdapter;<br>
+};<br>
+<br>
+struct D3DKMT_<wbr>OPENADAPTERFROMDEVICENAME {<br>
+    const WCHAR *pDeviceName;<br>
+    D3D_HANDLE hAdapter;<br>
+    LUID AdapterLuid;<br>
+};<br>
+<br>
+struct D3DKMT_<wbr>OPENADAPTERFROMGDIDISPLAYNAME {<br>
+    WCHAR DeviceName[32];<br>
+    D3D_HANDLE hAdapter;<br>
+    LUID AdapterLuid;<br>
+    UINT VidPnSourceId;<br>
+};<br>
+<br>
 struct QXLMonitorEscape {<br>
     QXLMonitorEscape(DEVMODE* dev_mode)<br>
     {<br>
@@ -174,10 +222,43 @@ struct QxlCustomEscapeObj : public QXLEscapeSetCustomDisplay {<br>
     QxlCustomEscapeObj() {};<br>
 };<br>
<br>
+struct WDDMCustomDisplayEscape {<br>
+    WDDMCustomDisplayEscape(<wbr>DEVMODE* dev_mode)<br>
+    {<br>
+        _ioctl = QXL_ESCAPE_SET_CUSTOM_DISPLAY;<br>
+        _custom.bpp  = dev_mode->dmBitsPerPel;<br>
+        _custom.xres = dev_mode->dmPelsWidth;<br>
+        _custom.yres = dev_mode->dmPelsHeight;<br>
+    }<br>
+    int                         _ioctl;<br>
+    QXLEscapeSetCustomDisplay   _custom;<br>
+};<br>
+<br>
+struct WDDMMonitorConfigEscape {<br>
+    WDDMMonitorConfigEscape(<wbr>DisplayMode* mode)<br>
+    {<br>
+        _ioctl = QXL_ESCAPE_MONITOR_CONFIG;<br>
+        _<a href="http://head.id" rel="noreferrer" target="_blank">head.id</a> = _head.surface_id = 0;<br>
+        _head.x = mode->get_pos_x();<br>
+        _head.y = mode->get_pos_y();<br>
+        _head.width = mode->get_width();<br>
+        _head.height = mode->get_height();<br>
+    }<br>
+    int         _ioctl;<br>
+    QXLHead     _head;<br>
+};<br>
+<br>
 DisplayConfig* DisplayConfig::create_config()<br>
 {<br>
     DisplayConfig* new_interface;<br>
-    new_interface = new XPDMInterface();<br>
+    /* Try to open a WDDM adapter.<br>
+    If that failed, assume we have an XPDM driver */<br>
+    try {<br>
+        new_interface = new  WDDMInterface();<br>
+    }<br>
+    catch (std::exception& e) {<br>
+        new_interface = new XPDMInterface();<br>
+    }<br>
     return new_interface;<br>
 }<br>
<br>
@@ -326,6 +407,278 @@ bool XPDMInterface::find_best_mode(<wbr>LPCTSTR Device, DEVMODE* dev_mode)<br>
     return NT_SUCCESS(status);<br>
 }<br>
<br>
+WDDMInterface::WDDMInterface(<wbr>)<br>
+    : _pfnOpen_adapter_hdc(NULL)<br>
+    , _pfnClose_adapter(NULL)<br>
+    , _pfnEscape(NULL)<br>
+    , _pfnOpen_adapter_device_name(<wbr>NULL)<br>
+    , _pfnOpen_adapter_gdi_name(<wbr>NULL)<br>
+{<br>
+    LONG error(0);<br>
+    //Can we find the D3D calls we need?<br>
+    if (!init_d3d_api()) {<br>
+        throw std::exception();<br>
+    }<br>
+<br>
+    //Initialize  CCD path stuff<br>
+    if (!_ccd.query_display_config()) {<br>
+        throw std::exception();<br>
+    }<br>
+<br>
+    if (!_ccd.set_display_config(<wbr>error)) {<br>
+        throw std::exception();<br>
+    }<br>
+}<br>
+<br>
+bool WDDMInterface::is_attached(<wbr>DISPLAY_DEVICE* dev_info)<br>
+{<br>
+    return _ccd.is_attached(dev_info-><wbr>DeviceName);<br>
+}<br>
+<br>
+bool WDDMInterface::set_monitor_<wbr>state(LPCTSTR device_name, DEVMODE* dev_mode, MONITOR_STATE state)<br>
+{<br>
+   return  _ccd.set_path_state(device_<wbr>name, state);<br>
+}<br>
+<br>
+bool WDDMInterface::custom_display_<wbr>escape(LPCTSTR device_name, DEVMODE* dev_mode)<br>
+{<br>
+    DISPLAYCONFIG_MODE_INFO* mode = _ccd.get_active_mode(device_<wbr>name, false);<br>
+    if (!mode) {<br>
+        return false;<br>
+    }<br>
+<br>
+    //Don't bother if we are already set to the new resolution<br>
+    if (mode->sourceMode.width == dev_mode->dmPelsWidth &&<br>
+        mode->sourceMode.height == dev_mode->dmPelsHeight) {<br>
+        return true;<br>
+    }<br>
+<br>
+    vd_printf("%s: updating %S resolution\n", __FUNCTION__, device_name);<br>
+<br>
+    WDDMCustomDisplayEscape wddm_escape(dev_mode);<br>
+    if (escape(device_name, &wddm_escape, sizeof(wddm_escape))) {<br>
+        return _ccd.update_mode_size(device_<wbr>name, dev_mode);<br>
+    }<br>
+<br>
+    vd_printf("%s: (%dx%d)", __FUNCTION__, mode->sourceMode.width, mode->sourceMode.height);<br>
+    return false;<br>
+}<br>
+<br>
+bool WDDMInterface::update_monitor_<wbr>config(LPCTSTR device_name, DisplayMode* display_mode,<br>
+                                           DEVMODE* dev_mode)<br>
+{<br>
+    if (!display_mode || !display_mode->get_attached()) {<br>
+        return false;<br>
+    }<br>
+    DISPLAYCONFIG_MODE_INFO* mode = _ccd.get_active_mode(device_<wbr>name, false);<br>
+    if (!mode || !_send_monitors_config)<br>
+        return false;<br>
+<br>
+    WDDMMonitorConfigEscape wddm_escape(display_mode);<br>
+    if (escape(device_name, &wddm_escape, sizeof(wddm_escape))) {<br>
+        //Update the path position<br>
+        return _ccd.update_mode_position(<wbr>device_name, dev_mode);<br>
+    }<br>
+<br>
+    vd_printf("%s: %S failed", __FUNCTION__, device_name);<br>
+    return false;<br>
+<br>
+}<br>
+<br>
+LONG WDDMInterface::update_display_<wbr>settings()<br>
+{<br>
+    LONG error(0);<br>
+    //If we removed the primary monitor since the last call, we need to<br>
+    //reorder the other monitors, making the leftmost one the primary<br>
+    _ccd.verify_primary_position()<wbr>;<br>
+    _ccd.set_display_config(error)<wbr>;<br>
+    return error;<br>
+}<br>
+<br>
+void WDDMInterface::update_config_<wbr>path()<br>
+{<br>
+    _ccd.query_display_config();<br>
+}<br>
+<br>
+bool WDDMInterface::update_dev_<wbr>mode_position(LPCTSTR device_name, DEVMODE* dev_mode,<br>
+                                             LONG x, LONG y)<br>
+{<br>
+    //Convert the position so that the primary is always at (0,0)<br>
+    dev_mode->dmPosition.x = x;<br>
+    dev_mode->dmPosition.y = y;<br>
+    return _ccd.update_mode_position(<wbr>device_name, dev_mode);<br>
+}<br>
+<br>
+bool WDDMInterface::init_d3d_api()<br>
+{<br>
+    HMODULE hModule = LoadLibrary(L"gdi32.dll");<br>
+<br>
+    //Look for the gdi32 functions we need to perform driver escapes<br>
+    if (!hModule) {<br>
+        vd_printf("%s something wildly wrong as we can't open gdi32.dll", __FUNCTION__);<br>
+        return false;<br>
+    }<br>
+<br>
+    do {<br>
+        _pfnClose_adapter = (PFND3DKMT_CLOSEADAPTER)<br>
+            GetProcAddress(hModule, "D3DKMTCloseAdapter");<br>
+        if (!_pfnClose_adapter) {<br>
+            break;<br>
+        }<br>
+<br>
+        _pfnEscape = (PFND3DKMT_ESCAPE) GetProcAddress(hModule, "D3DKMTEscape");<br>
+        if (!_pfnEscape) {<br>
+            break;<br>
+        }<br>
+<br>
+        _pfnOpen_adapter_hdc = (PFND3DKMT_OPENADAPTERFROMHDC)<br>
+            GetProcAddress(hModule, "D3DKMTOpenAdapterFromHdc");<br>
+        if (!_pfnOpen_adapter_hdc) {<br>
+            break;<br>
+        }<br>
+<br>
+        _pfnOpen_adapter_device_name = (PFND3DKMT_<wbr>OPENADAPTERFROMDEVICENAME)<br>
+            GetProcAddress(hModule, "<wbr>D3DKMTOpenAdapterFromDeviceNam<wbr>e");<br>
+        if (!_pfnOpen_adapter_device_<wbr>name) {<br>
+            break;<br>
+        }<br>
+<br>
+        _pfnOpen_adapter_gdi_name = (PFND3DKMT_<wbr>OPENADAPTERFROMGDIDISPLAYNAME)<br>
+            GetProcAddress(hModule, "<wbr>D3DKMTOpenAdapterFromGdiDispla<wbr>yName");<br>
+        if (!_pfnOpen_adapter_gdi_name) {<br>
+            break;<br>
+        }<br>
+<br>
+    }<br>
+    while(0);<br>
+<br>
+    FreeLibrary(hModule);<br>
+<br>
+    //Did we get them ?<br>
+    if (!_pfnClose_adapter || !_pfnOpen_adapter_hdc || !_pfnEscape)  {<br>
+        return false;<br>
+    }<br>
+    return true;<br>
+}<br>
+<br>
+D3D_HANDLE WDDMInterface::adapter_handle(<wbr>LPCTSTR device_name)<br>
+{<br>
+    D3D_HANDLE hAdapter(0);<br>
+<br>
+    //For some reason, unknown to me, this call will occasionally fail.<br>
+    if ((hAdapter = handle_from_DC(device_name))) {<br>
+        return hAdapter;<br>
+    }<br>
+        //So try other available methods.<br>
+    if (_pfnOpen_adapter_device_name && (hAdapter = handle_from_device_name(<wbr>device_name))) {<br>
+        return hAdapter;<br>
+    }<br>
+    //One last chance to open this guy<br>
+    if (_pfnOpen_adapter_gdi_name) {<br>
+        hAdapter = handle_from_GDI_name(device_<wbr>name);<br>
+    }<br>
+<br>
+    if (!hAdapter) {<br>
+        vd_printf("%s: failed to open adapter %S", __FUNCTION__, device_name);<br>
+    }<br>
+<br>
+    return hAdapter;<br>
+}<br>
+<br>
+D3D_HANDLE WDDMInterface::handle_from_DC(<wbr>LPCTSTR adapter_name)<br>
+{<br>
+    NTSTATUS status;<br>
+    D3DKMT_OPENADAPTERFROMHDC open_data;<br>
+    HDC hDc(CreateDC(adapter_name, NULL, NULL, NULL));<br>
+<br>
+    if (!hDc) {<br>
+        vd_printf("%s: %S CreateDC failed with %lu", __FUNCTION__, adapter_name, GetLastError());<br>
+        return 0;<br>
+    }<br>
+<br>
+    ZeroMemory(&open_data, sizeof(D3DKMT_<wbr>OPENADAPTERFROMHDC));<br>
+    open_data.hDc = hDc;<br>
+<br>
+    if (!NT_SUCCESS(status = _pfnOpen_adapter_hdc(&open_<wbr>data))) {<br>
+        vd_printf("%s: %S open adapter from hdc failed with %lu", __FUNCTION__, adapter_name,<br>
+            status);<br>
+        open_data.hAdapter = 0;<br>
+    }<br>
+<br>
+    DeleteDC(hDc);<br>
+    return open_data.hAdapter;<br>
+}<br>
+<br>
+D3D_HANDLE WDDMInterface::handle_from_<wbr>device_name(LPCTSTR adapter_name)<br>
+{<br>
+    D3DKMT_<wbr>OPENADAPTERFROMDEVICENAME display_name_data;<br>
+    NTSTATUS  status;<br>
+<br>
+    ZeroMemory(&display_name_data, sizeof(display_name_data));<br>
+    display_name_data.pDeviceName = adapter_name;<br>
+<br>
+    if (NT_SUCCESS(status = _pfnOpen_adapter_device_name(&<wbr>display_name_data))) {<br>
+        return display_name_data.hAdapter;<br>
+    }<br>
+<br>
+    vd_printf("%s %S failed with 0x%lx", __FUNCTION__, adapter_name, status);<br>
+    return 0;<br>
+}<br>
+<br>
+D3D_HANDLE WDDMInterface::handle_from_<wbr>GDI_name(LPCTSTR adapter_name)<br>
+{<br>
+    D3DKMT_<wbr>OPENADAPTERFROMGDIDISPLAYNAME gdi_display_name;<br>
+    NTSTATUS status;<br>
+<br>
+    ZeroMemory(&gdi_display_name, sizeof(gdi_display_name));<br>
+    memcpy((void *) gdi_display_name.DeviceName, adapter_name, sizeof(TCHAR)* CCHDEVICENAME);<br>
+<br>
+    if (NT_SUCCESS(status = _pfnOpen_adapter_gdi_name(&<wbr>gdi_display_name))) {<br>
+        return  gdi_display_name.hAdapter;<br>
+    }<br>
+<br>
+    vd_printf("%s: %S aurrrgghh nothing works..error  is 0x%lx", __FUNCTION__, adapter_name,<br>
+            status);<br>
+    return 0;<br>
+}<br>
+<br>
+void WDDMInterface::close_adapter(<wbr>D3D_HANDLE handle)<br>
+{<br>
+    D3DKMT_CLOSEADAPTER closeData;<br>
+    if (handle) {<br>
+        closeData.hAdapter = handle;<br>
+        _pfnClose_adapter(&closeData);<br>
+    }<br>
+}<br>
+<br>
+bool WDDMInterface::escape(LPCTSTR device_name, void* data, UINT size_data)<br>
+{<br>
+    D3DKMT_ESCAPE   escapeData;<br>
+    NTSTATUS        status;<br>
+    D3D_HANDLE   hAdapter(0);<br>
+<br>
+    if (!(hAdapter = adapter_handle(device_name)))<br>
+        return false;<br>
+<br>
+    escapeData.hAdapter = hAdapter;<br>
+    escapeData.hDevice = 0;<br>
+    escapeData.hContext = 0;<br>
+    escapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;<br>
+    escapeData.Flags.Value = 0;<br>
+    escapeData.pPrivateDriverData = data;<br>
+    escapeData.<wbr>PrivateDriverDataSize = size_data;<br>
+<br>
+    status = _pfnEscape(&escapeData);<br>
+<br>
+    if (!NT_SUCCESS(status)) {<br>
+        vd_printf("%s: this should never happen. Status is 0x%lx", __FUNCTION__, status);<br>
+    }<br>
+<br>
+    //Close the handle to this device<br>
+    close_adapter(hAdapter);<br>
+    return NT_SUCCESS(status);<br>
+}<br>
+<br>
 CCD::CCD()<br>
     :_numPathElements(0)<br>
     ,_numModeElements(0)<br>
diff --git a/vdagent/display_<wbr>configuration.h b/vdagent/display_<wbr>configuration.h<br>
index 05b35f4..e5ee90d 100755<br>
--- a/vdagent/display_<wbr>configuration.h<br>
+++ b/vdagent/display_<wbr>configuration.h<br>
@@ -125,4 +125,51 @@ private:<br>
     bool find_best_mode(LPCTSTR Device, DEVMODE* dev_mode);<br>
 };<br>
<br>
+//DisplayConfig implementation for guest with WDDM graphics drivers<br>
+typedef UINT D3D_HANDLE;<br>
+<br>
+struct D3DKMT_ESCAPE;<br>
+struct D3DKMT_<wbr>OPENADAPTERFROMGDIDISPLAYNAME;<br>
+struct D3DKMT_<wbr>OPENADAPTERFROMDEVICENAME;<br>
+struct D3DKMT_CLOSEADAPTER;<br>
+struct D3DKMT_OPENADAPTERFROMHDC;<br>
+<br>
+typedef NTSTATUS(APIENTRY* PFND3DKMT_ESCAPE)(CONST D3DKMT_ESCAPE*);<br>
+typedef NTSTATUS(APIENTRY* PFND3DKMT_<wbr>OPENADAPTERFROMGDIDISPLAYNAME)<wbr>(D3DKMT_<wbr>OPENADAPTERFROMGDIDISPLAYNAME*<wbr>);<br>
+typedef NTSTATUS(APIENTRY* PFND3DKMT_<wbr>OPENADAPTERFROMDEVICENAME)(<wbr>D3DKMT_<wbr>OPENADAPTERFROMDEVICENAME*);<br>
+typedef NTSTATUS(APIENTRY* PFND3DKMT_CLOSEADAPTER)(<wbr>D3DKMT_CLOSEADAPTER*);<br>
+typedef NTSTATUS(APIENTRY* PFND3DKMT_OPENADAPTERFROMHDC)(<wbr>D3DKMT_OPENADAPTERFROMHDC*);<br>
+<br>
+class WDDMInterface : public DisplayConfig {<br>
+public:<br>
+    WDDMInterface();<br>
+    bool is_attached(DISPLAY_DEVICE* dev_info);<br>
+    bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode, MONITOR_STATE state);<br>
+    LONG update_display_settings();<br>
+    bool custom_display_escape(LPCTSTR device_name, DEVMODE* dev_mode);<br>
+    bool update_monitor_config(LPCTSTR device_name, DisplayMode* mode, DEVMODE* dev_mode);<br>
+    bool update_dev_mode_position(<wbr>LPCTSTR device_name, DEVMODE * dev_mode, LONG x, LONG y);<br>
+    void update_config_path();<br>
+<br>
+private:<br>
+    bool init_d3d_api();<br>
+    D3D_HANDLE adapter_handle(LPCTSTR device_name);<br>
+    D3D_HANDLE handle_from_DC(LPCTSTR adapter_name);<br>
+    D3D_HANDLE handle_from_device_name(<wbr>LPCTSTR adapter_name);<br>
+    D3D_HANDLE handle_from_GDI_name(LPCTSTR adapter_name);<br>
+<br>
+    void close_adapter(D3D_HANDLE handle);<br>
+    bool escape(LPCTSTR device_name, void* data, UINT sizeData);<br>
+<br>
+    //GDI Function pointers<br>
+    PFND3DKMT_OPENADAPTERFROMHDC _pfnOpen_adapter_hdc;<br>
+    PFND3DKMT_CLOSEADAPTER  _pfnClose_adapter;<br>
+    PFND3DKMT_ESCAPE _pfnEscape;<br>
+    PFND3DKMT_<wbr>OPENADAPTERFROMDEVICENAME _pfnOpen_adapter_device_name;<br>
+    PFND3DKMT_<wbr>OPENADAPTERFROMGDIDISPLAYNAME _pfnOpen_adapter_gdi_name;<br>
+<br>
+    //object handles the CCD API<br>
+    CCD _ccd;<br>
+};<br>
+<br>
 #endif<br>
\ No newline at end of file<br>
--<br>
2.7.4<br>
<br>
</blockquote></div></div>