[Spice-devel] [PATCH win-vdagent] Provide support for Windows CCD API
Frediano Ziglio
fziglio at redhat.com
Wed Aug 3 09:25:59 UTC 2016
> Thanks for the review, comments are inline.
> On Tue, Aug 2, 2016 at 4:31 PM, Frediano Ziglio < fziglio at redhat.com > wrote:
> > >
>
> > > The Connecting and Configuring Displays (CCD) Win32 APIs
>
> > > provide more control over the desktop display setup. The CCD APIs
>
> > > move away from using Windows Graphics Device Interface (GDI)
>
> > > concepts like view name and toward Windows Display Driver Model
>
> > > (WDDM) concepts like adapter, source, and target identifiers.
>
> > > More info on the CCD API can be found here:
>
> > > https://msdn.microsoft.com/en-us/library/windows/hardware/ff539590(v=vs.85).aspx
>
> > >
>
> > > This patch introduces partial functionality from the CCD API
>
> > > needed by vdagent. It is needed by vdagent in order to support
>
> > > multiple monitors and arbitrary resolution on Windows 10.
>
> > >
>
> > > Tested with both Windows 10 and Windows 7.
>
> > >
>
> > > Based on a patch by Sandy Stutsman < sstutsma at redhat.com >
>
> > >
>
> > > Signed-off-by: Dmitry Fleytman < dfleytma at redhat.com >
>
> > > Signed-off-by: Sameeh Jubran < sameeh at daynix.com >
>
> > > ---
>
> > > Makefile.am | 2 +
>
> > > vdagent/desktop_layout.cpp | 150 ++----
>
> > > vdagent/desktop_layout.h | 9 +-
>
> > > vdagent/display_configuration.cpp | 1071
>
> > > +++++++++++++++++++++++++++++++++++++
>
> > > vdagent/display_configuration.h | 191 +++++++
>
> > > 5 files changed, 1301 insertions(+), 122 deletions(-)
>
> > > create mode 100755 vdagent/display_configuration.cpp
>
> > > create mode 100755 vdagent/display_configuration.h
>
> > >
>
> > > diff --git a/Makefile.am b/Makefile.am
>
> > > index c3fc6bf..84507e8 100644
>
> > > --- a/Makefile.am
>
> > > +++ b/Makefile.am
>
> > > @@ -31,6 +31,8 @@ vdagent_SOURCES = \
>
> > > common/vdcommon.h \
>
> > > common/vdlog.cpp \
>
> > > common/vdlog.h \
>
> > > + vdagent/display_configuration.cpp \
>
> > > + vdagent/display_configuration.h \
>
> > > vdagent/desktop_layout.cpp \
>
> > > vdagent/desktop_layout.h \
>
> > > vdagent/display_setting.cpp \
>
> > > diff --git a/vdagent/desktop_layout.cpp b/vdagent/desktop_layout.cpp
>
> > > index a7666ca..e59a1a4 100644
>
> > > --- a/vdagent/desktop_layout.cpp
>
> > > +++ b/vdagent/desktop_layout.cpp
>
> > > @@ -18,6 +18,7 @@
>
> > > #include <spice/qxl_windows.h>
>
> > > #include <spice/qxl_dev.h>
>
> > > #include "desktop_layout.h"
>
> > > +#include "display_configuration.h"
>
> > > #include "vdlog.h"
>
> > >
>
> > > #ifdef __MINGW32__
>
> > > @@ -35,15 +36,19 @@ void DisplayMode::set_res(DWORD width, DWORD height,
>
> > > DWORD depth)
>
> > > DesktopLayout::DesktopLayout()
>
> > > : _total_width (0)
>
> > > , _total_height (0)
>
> > > - , _send_monitors_position(false)
>
> > > + , _display_config (NULL)
>
> > > {
>
> > > MUTEX_INIT(_mutex);
>
> > > + _display_config = DisplayConfig::create_config();
>
> > > get_displays();
>
> > > }
>
> > >
>
> > > DesktopLayout::~DesktopLayout()
>
> > > {
>
> > > clean_displays();
>
> > > + if (_display_config) {
>
> > > + delete _display_config;
>
> > > + }
>
> > just delete _display_config, the if is redundant.
>
> > > }
>
> > >
>
> > > void DesktopLayout::get_displays()
>
> > > @@ -59,6 +64,7 @@ void DesktopLayout::get_displays()
>
> > > unlock();
>
> > > return;
>
> > > }
>
> > > + _display_config->update_config_path();
>
> > > clean_displays();
>
> > > ZeroMemory(&dev_info, sizeof(dev_info));
>
> > > dev_info.cb = sizeof(dev_info);
>
> > > @@ -82,12 +88,13 @@ void DesktopLayout::get_displays()
>
> > > _displays[i] = NULL;
>
> > > }
>
> > > }
>
> > > - attached = !!(dev_info.StateFlags &
>
> > > DISPLAY_DEVICE_ATTACHED_TO_DESKTOP);
>
> > > + attached = _display_config->is_attached(&dev_info);
>
> > > +
>
> > > EnumDisplaySettings(dev_info.DeviceName, ENUM_CURRENT_SETTINGS,
>
> > > &mode);
>
> > > _displays[display_id] = new DisplayMode(mode.dmPosition.x,
>
> > > mode.dmPosition.y,
>
> > > mode.dmPelsWidth,
>
> > > mode.dmPelsHeight,
>
> > > mode.dmBitsPerPel,
>
> > > attached);
>
> > > - update_monitor_config(dev_info.DeviceName, _displays[display_id]);
>
> > > + _display_config->update_monitor_config(dev_info.DeviceName,
>
> > > _displays[display_id], &mode);
>
> > > }
>
> > > normalize_displays_pos();
>
> > > unlock();
>
> > > @@ -121,6 +128,7 @@ void DesktopLayout::set_displays()
>
> > > unlock();
>
> > > return;
>
> > > }
>
> > > + _display_config->update_config_path();
>
> > > ZeroMemory(&dev_info, sizeof(dev_info));
>
> > > dev_info.cb = sizeof(dev_info);
>
> > > ZeroMemory(&dev_mode, sizeof(dev_mode));
>
> > > @@ -146,28 +154,32 @@ void DesktopLayout::set_displays()
>
> > > break;
>
> > > }
>
> > > DisplayMode * mode(_ displays.at (display_id));
>
> > > - if (!init_dev_mode(dev_info.DeviceName, &dev_mode, mode, normal_x,
>
> > > normal_y, true)) {
>
> > > + if (!init_dev_mode(dev_info.DeviceName, &dev_mode, mode)) {
>
> > > vd_printf("No suitable mode found for display %S",
>
> > > dev_info.DeviceName);
>
> > > break;
>
> > > }
>
> > > vd_printf("Set display mode %lux%lu", dev_mode.dmPelsWidth,
>
> > > dev_mode.dmPelsHeight);
>
> > > - LONG ret = ChangeDisplaySettingsEx(dev_info.DeviceName, &dev_mode,
>
> > > NULL,
>
> > > - CDS_UPDATEREGISTRY | CDS_NORESET,
>
> > > NULL);
>
> > > - if (ret == DISP_CHANGE_SUCCESSFUL) {
>
> > > + if (_display_config->update_dev_mode_position(dev_info.DeviceName,
>
> > > &dev_mode,
>
> > > + mode->_pos_x -
>
> > > normal_x,
>
> > > + mode->_pos_y -
>
> > > normal_y)) {
>
> > > dev_sets++;
>
> > > - update_monitor_config(dev_info.DeviceName, mode);
>
> > > + _display_config->update_monitor_config(dev_info.DeviceName,
>
> > > mode, &dev_mode);
>
> > > }
>
> > > if (!is_qxl) {
>
> > > display_id++;
>
> > > }
>
> > > }
>
> > > if (dev_sets) {
>
> > > - ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
>
> > > + _display_config->update_display_settings();
>
> > > normalize_displays_pos();
>
> > > }
>
> > > unlock();
>
> > > }
>
> > >
>
> > > +void DesktopLayout::set_position_configurable(bool flag) {
>
> > > + _display_config->set_monitors_config(flag);
>
> > > +}
>
> > > +
>
> > > // Normalize all display positions to non-negative coordinates and update
>
> > > total width and height of
>
> > > // the virtual desktop. Caller is responsible to lock() & unlock().
>
> > > void DesktopLayout::normalize_displays_pos()
>
> > > @@ -265,125 +277,29 @@ bool DesktopLayout::get_qxl_device_id(WCHAR*
>
> > > device_key, DWORD* device_id)
>
> > > return key_found;
>
> > > }
>
> > >
>
> > > -bool DesktopLayout::init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode,
>
> > > DisplayMode* mode,
>
> > > - LONG normal_x, LONG normal_y, bool
>
> > > set_pos)
>
> > > +bool DesktopLayout::init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode,
>
> > > DisplayMode* mode)
>
> > > {
>
> > > - DWORD closest_diff = -1;
>
> > > - DWORD best = -1;
>
> > > - QXLEscapeSetCustomDisplay custom;
>
> > > - HDC hdc = NULL;
>
> > > - LONG ret;
>
> > > -
>
> > > ZeroMemory(dev_mode, sizeof(DEVMODE));
>
> > > dev_mode->dmSize = sizeof(DEVMODE);
>
> > > - if (!mode || !mode->_attached) {
>
> > > - //Detach monitor
>
> > > - dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
>
> > > - return true;
>
> > > - }
>
> > > -
>
> > > - hdc = CreateDC(dev_name, NULL, NULL, NULL);
>
> > > - if (!hdc) {
>
> > > - // for some reason, windows want those 3 flags to enable monitor
>
> > > - dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
>
> > > - dev_mode->dmPelsWidth = mode->_width;
>
> > > - dev_mode->dmPelsHeight = mode->_height;
>
> > > - ret = ChangeDisplaySettingsEx(dev_name, dev_mode, NULL,
>
> > > CDS_UPDATEREGISTRY, NULL);
>
> > > - if (ret == DISP_CHANGE_BADMODE) {
>
> > > - // custom resolution might not be set yet, use known resolution
>
> > > - // FIXME: this causes client temporary resize... a
>
> > > - // solution would involve passing custom resolution before
>
> > > - // driver initialization, perhaps through registry
>
> > > - dev_mode->dmPelsWidth = 640;
>
> > > - dev_mode->dmPelsHeight = 480;
>
> > > - ret = ChangeDisplaySettingsEx(dev_name, dev_mode, NULL,
>
> > > CDS_UPDATEREGISTRY, NULL);
>
> > > - }
>
> > > -
>
> > > - vd_printf("attach %ld", ret);
>
> > > - hdc = CreateDC(dev_name, NULL, NULL, NULL);
>
> > > - }
>
> > >
>
> > > - if (!hdc) {
>
> > > - vd_printf("failed to create DC");
>
> > > - return false;
>
> > > - } else {
>
> > > - // Update custom resolution
>
> > > - custom.xres = mode->_width;
>
> > > - custom.yres = mode->_height;
>
> > > - custom.bpp = mode->_depth;
>
> > > -
>
> > > - int err = ExtEscape(hdc, QXL_ESCAPE_SET_CUSTOM_DISPLAY,
>
> > > - sizeof(QXLEscapeSetCustomDisplay),
>
> > > (LPCSTR)&custom, 0, NULL);
>
> > > - if (err <= 0) {
>
> > > - vd_printf("can't set custom display, perhaps an old driver");
>
> > > - }
>
> > > - DeleteDC(hdc);
>
> > > + //Update monitor state
>
> > > + MONITOR_STATE monitor_state = (!mode || !mode->_attached)?
>
> > > MONITOR_DETACHED : MONITOR_ATTACHED;
>
> > > + _display_config->set_monitor_state(dev_name, dev_mode, monitor_state);
>
> > > + if (monitor_state == MONITOR_DETACHED) {
>
> > > + return true;
>
> > > }
>
> > >
>
> > > - // force refresh mode table
>
> > > - DEVMODE tempDevMode;
>
> > > - ZeroMemory(&tempDevMode, sizeof (tempDevMode));
>
> > > - tempDevMode.dmSize = sizeof(DEVMODE);
>
> > > - EnumDisplaySettings(dev_name, 0xffffff, &tempDevMode);
>
> > > -
>
> > > - //Find the closest size which will fit within the monitor
>
> > > - for (DWORD i = 0; EnumDisplaySettings(dev_name, i, dev_mode); i++) {
>
> > > - if (dev_mode->dmPelsWidth > mode->_width ||
>
> > > - dev_mode->dmPelsHeight > mode->_height ||
>
> > > - dev_mode->dmBitsPerPel != mode->_depth) {
>
> > > - continue;
>
> > > - }
>
> > > - DWORD wdiff = mode->_width - dev_mode->dmPelsWidth;
>
> > > - DWORD hdiff = mode->_height - dev_mode->dmPelsHeight;
>
> > > - DWORD diff = wdiff * wdiff + hdiff * hdiff;
>
> > > - if (diff < closest_diff) {
>
> > > - closest_diff = diff;
>
> > > - best = i;
>
> > > - }
>
> > > - }
>
> > > - if (best == (DWORD)-1 || !EnumDisplaySettings(dev_name, best,
> > > dev_mode))
>
> > > {
>
> > > + // Update custom resolution
>
> > > + dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
>
> > > + dev_mode->dmPelsWidth = mode->_width;
>
> > > + dev_mode->dmPelsHeight = mode->_height;
>
> > > + dev_mode->dmBitsPerPel = mode->_depth;
>
> > > + if (!_display_config->custom_display_escape(dev_name, dev_mode))
>
> > > return false;
>
> > > - }
>
> > > - dev_mode->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
>
> > > - if (set_pos) {
>
> > > - //Convert the position so that the primary is always at (0,0)
>
> > > - dev_mode->dmPosition.x = mode->_pos_x - normal_x;
>
> > > - dev_mode->dmPosition.y = mode->_pos_y - normal_y;
>
> > > - dev_mode->dmFields |= DM_POSITION;
>
> > > - }
>
> > >
>
> > > // update current DisplayMode (so mouse scaling works properly)
>
> > > mode->_width = dev_mode->dmPelsWidth;
>
> > > mode->_height = dev_mode->dmPelsHeight;
>
> > > -
>
> > > return true;
>
> > > -}
>
> > > -
>
> > > -bool DesktopLayout::update_monitor_config(LPCTSTR dev_name, DisplayMode*
>
> > > mode)
>
> > > -{
>
> > > - QXLHead monitor_config;
>
> > > -
>
> > > - if (!mode || !mode->get_attached())
>
> > > - return false;
>
> > > -
>
> > > - //Don't configure monitors unless the client supports it
>
> > > - if(!_send_monitors_position) return FALSE;
>
> > > -
>
> > > - HDC hdc = CreateDC(dev_name, NULL, NULL, NULL);
>
> > > -
>
> > > - memset(&monitor_config, 0, sizeof(monitor_config));
>
> > > - monitor_config.x = mode->_pos_x;
>
> > > - monitor_config.y = mode->_pos_y;
>
> > > - monitor_config.width = mode->_width;
>
> > > - monitor_config.height = mode->_height;
>
> > > -
>
> > > - int err = ExtEscape(hdc, QXL_ESCAPE_MONITOR_CONFIG,
>
> > > - sizeof(QXLHead), (LPCSTR) &monitor_config, 0, NULL);
>
> > > -
>
> > > - if (err < 0){
>
> > > - vd_printf("can't update monitor config, may have an older driver");
>
> > > - }
>
> > >
>
> > > - DeleteDC(hdc);
>
> > > - return (err >= 0);
>
> > > }
>
> > > diff --git a/vdagent/desktop_layout.h b/vdagent/desktop_layout.h
>
> > > index ece3946..fd6af76 100644
>
> > > --- a/vdagent/desktop_layout.h
>
> > > +++ b/vdagent/desktop_layout.h
>
> > > @@ -60,6 +60,7 @@ private:
>
> > > };
>
> > >
>
> > > typedef std::vector<DisplayMode*> Displays;
>
> > > +class DisplayConfig;
>
> > >
>
> > > class DesktopLayout {
>
> > > public:
>
> > > @@ -73,23 +74,21 @@ public:
>
> > > size_t get_display_count() { return _displays.size();}
>
> > > DWORD get_total_width() { return _total_width;}
>
> > > DWORD get_total_height() { return _total_height;}
>
> > > - void set_position_configurable(bool flag) { _send_monitors_position =
>
> > > flag; }
>
> > > + void set_position_configurable(bool flag);
>
> > > private:
>
> > > void clean_displays();
>
> > > void normalize_displays_pos();
>
> > > DisplayMode * get_primary_display();
>
> > > - bool update_monitor_config(LPCTSTR dev_name, DisplayMode* mode);
>
> > > + bool init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode, DisplayMode*
>
> > > mode);
>
> > > static bool consistent_displays();
>
> > > static bool is_attached(LPCTSTR dev_name);
>
> > > static bool get_qxl_device_id(WCHAR* device_key, DWORD* device_id);
>
> > > - static bool init_dev_mode(LPCTSTR dev_name, DEVMODE* dev_mode,
>
> > > DisplayMode* mode,
>
> > > - LONG normal_x, LONG normal_y, bool set_pos);
>
> > > private:
>
> > > mutex_t _mutex;
>
> > > Displays _displays;
>
> > > DWORD _total_width;
>
> > > DWORD _total_height;
>
> > > - bool _send_monitors_position;
>
> > > + DisplayConfig* _display_config;
>
> > > };
>
> > >
>
> > > #endif
>
> > > diff --git a/vdagent/display_configuration.cpp
>
> > > b/vdagent/display_configuration.cpp
>
> > > new file mode 100755
>
> > > index 0000000..563f619
>
> > > --- /dev/null
>
> > > +++ b/vdagent/display_configuration.cpp
>
> > > @@ -0,0 +1,1071 @@
>
> > > +/*
>
> > > +Copyright (C) 2015 Red Hat, Inc.
>
> > > +
>
> > > +This program is free software; you can redistribute it and/or
>
> > > +modify it under the terms of the GNU General Public License as
>
> > > +published by the Free Software Foundation; either version 2 of
>
> > > +the License, or (at your option) any later version.
>
> > > +
>
> > > +This program is distributed in the hope that it will be useful,
>
> > > +but WITHOUT ANY WARRANTY; without even the implied warranty of
>
> > > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>
> > > +GNU General Public License for more details.
>
> > > +
>
> > > +You should have received a copy of the GNU General Public License
>
> > > +along with this program. If not, see < http://www.gnu.org/licenses/ >.
>
> > > +*/
>
> > > +
>
> > > +#include "display_configuration.h"
>
> > > +#include <winternl.h>
>
> > > +
>
> > > +//
>
> > > +// Definitions used by QueryDisplayConfig.
>
> > > +//
>
> > > +
>
> > > +#define QDC_ALL_PATHS 0x00000001
>
> > > +
>
> > > +//
>
> > > +// Definitions used by SetDisplayConfig.
>
> > > +//
>
> > > +
>
> > > +#define SDC_USE_SUPPLIED_DISPLAY_CONFIG 0x00000020
>
> > > +#define SDC_APPLY 0x00000080
>
> > > +#define SDC_FORCE_MODE_ENUMERATION 0x00001000
>
> > > +
>
> > > +#define DISPLAYCONFIG_PATH_ACTIVE 0x00000001
>
> > > +#define DISPLAYCONFIG_PATH_MODE_IDX_INVALID 0xffffffff
>
> > > +
>
> > > +enum DISPLAYCONFIG_DEVICE_INFO_TYPE {
>
> > > + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1
>
> > > +};
>
> > > +
>
> > > +enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY {};
>
> > > +
>
> > > +enum DISPLAYCONFIG_ROTATION {};
>
> > > +
>
> > > +enum DISPLAYCONFIG_SCANLINE_ORDERING {};
>
> > > +
>
> > > +enum DISPLAYCONFIG_SCALING {};
>
> > > +
>
> > > +enum DISPLAYCONFIG_PIXELFORMAT {};
>
> > > +
>
> > > +enum DISPLAYCONFIG_MODE_INFO_TYPE {};
>
> > > +
>
> > > +struct DISPLAYCONFIG_DEVICE_INFO_HEADER {
>
> > > + DISPLAYCONFIG_DEVICE_INFO_TYPE type;
>
> > > + UINT32 size;
>
> > > + LUID adapterId;
>
> > > + UINT32 id;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_SOURCE_DEVICE_NAME {
>
> > > + DISPLAYCONFIG_DEVICE_INFO_HEADER header;
>
> > > + WCHAR
>
> > > viewGdiDeviceName[CCHDEVICENAME];
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO {
>
> > > + POINTL PathSourceSize;
>
> > > + RECTL DesktopImageRegion;
>
> > > + RECTL DesktopImageClip;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_RATIONAL {
>
> > > + UINT32 Numerator;
>
> > > + UINT32 Denominator;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_2DREGION {
>
> > > + UINT32 cx;
>
> > > + UINT32 cy;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO {
>
> > > + UINT64 pixelRate;
>
> > > + DISPLAYCONFIG_RATIONAL hSyncFreq;
>
> > > + DISPLAYCONFIG_RATIONAL vSyncFreq;
>
> > > + DISPLAYCONFIG_2DREGION activeSize;
>
> > > + DISPLAYCONFIG_2DREGION totalSize;
>
> > > +
>
> > > + union {
>
> > > + struct {
>
> > > + UINT32 videoStandard : 16;
>
> > > + UINT32 vSyncFreqDivider : 6;
>
> > > + UINT32 reserved : 10;
>
> > > + } AdditionalSignalInfo;
>
> > > + UINT32 videoStandard;
>
> > > + } DUMMYUNIONNAME;
>
> > > + DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_TARGET_MODE {
>
> > > + DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_SOURCE_MODE {
>
> > > + UINT32 width;
>
> > > + UINT32 height;
>
> > > + DISPLAYCONFIG_PIXELFORMAT pixelFormat;
>
> > > + POINTL position;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_MODE_INFO {
>
> > > + DISPLAYCONFIG_MODE_INFO_TYPE infoType;
>
> > > + UINT32 id;
>
> > > + LUID adapterId;
>
> > > + union {
>
> > > + DISPLAYCONFIG_TARGET_MODE targetMode;
>
> > > + DISPLAYCONFIG_SOURCE_MODE sourceMode;
>
> > > + DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo;
>
> > > + } DUMMYUNIONNAME;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_PATH_SOURCE_INFO {
>
> > > + LUID adapterId;
>
> > > + UINT32 id;
>
> > > + union {
>
> > > + UINT32 modeInfoIdx;
>
> > > + struct {
>
> > > + UINT32 cloneGroupId : 16;
>
> > > + UINT32 sourceModeInfoIdx : 16;
>
> > > + } DUMMYSTRUCTNAME;
>
> > > + } DUMMYUNIONNAME;
>
> > > +
>
> > > + UINT32 statusFlags;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_PATH_TARGET_INFO {
>
> > > + LUID adapterId;
>
> > > + UINT32 id;
>
> > > + union {
>
> > > + UINT32 modeInfoIdx;
>
> > > + struct {
>
> > > + UINT32 desktopModeInfoIdx : 16;
>
> > > + UINT32 targetModeInfoIdx : 16;
>
> > > + } DUMMYSTRUCTNAME;
>
> > > + } DUMMYUNIONNAME;
>
> > > + DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
>
> > > + DISPLAYCONFIG_ROTATION rotation;
>
> > > + DISPLAYCONFIG_SCALING scaling;
>
> > > + DISPLAYCONFIG_RATIONAL refreshRate;
>
> > > + DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
>
> > > + BOOL targetAvailable;
>
> > > + UINT32 statusFlags;
>
> > > +};
>
> > > +
>
> > > +struct DISPLAYCONFIG_PATH_INFO {
>
> > > + DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
>
> > > + DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
>
> > > + UINT32 flags;
>
> > > +};
>
> > > +
>
> > > +
>
> > > +enum D3DKMT_ESCAPETYPE {
>
> > > + D3DKMT_ESCAPE_DRIVERPRIVATE = 0
>
> > > +};
>
> > > +
>
> > > +struct D3DDDI_ESCAPEFLAGS {
>
> > > + union {
>
> > > + struct {
>
> > > + UINT Reserved : 31;
>
> > > + };
>
> > > + UINT Value;
>
> > > + };
>
> > > +};
>
> > > +
>
> > > +struct D3DKMT_ESCAPE {
>
> > > + D3DKMT_HANDLE hAdapter;
>
> > > + D3DKMT_HANDLE hDevice;
>
> > > + D3DKMT_ESCAPETYPE Type;
>
> > > + D3DDDI_ESCAPEFLAGS Flags;
>
> > > + VOID* pPrivateDriverData;
>
> > > + UINT PrivateDriverDataSize;
>
> > > + D3DKMT_HANDLE hContext;
>
> > > +};
>
> > > +
>
> > > +typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;
>
> > > +
>
> > > +struct D3DKMT_OPENADAPTERFROMHDC {
>
> > > + HDC hDc;
>
> > > + D3DKMT_HANDLE hAdapter;
>
> > > + LUID AdapterLuid;
>
> > > + D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
>
> > > +};
>
> > > +
>
> > > +struct D3DKMT_CLOSEADAPTER {
>
> > > + D3DKMT_HANDLE hAdapter;
>
> > > +};
>
> > > +
>
> > > +struct D3DKMT_OPENADAPTERFROMDEVICENAME {
>
> > > + PCWSTR pDeviceName;
>
> > > + D3DKMT_HANDLE hAdapter;
>
> > > + LUID AdapterLuid;
>
> > > +};
>
> > > +
>
> > > +struct D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME {
>
> > > + WCHAR DeviceName[32];
>
> > > + D3DKMT_HANDLE hAdapter;
>
> > > + LUID AdapterLuid;
>
> > > + D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
>
> > > +};
>
> > > +
>
> > There are defined from Microsoft, better to move them in
>
> > a separate file. The license can changed easier.
>
> Can you please further explain regarding the licensing? which license should
> be used?
These defines came from Microsoft headers or from the web like
https://msdn.microsoft.com/en-us/library/windows/hardware/ff548113(v=vs.85).aspx
simply you can't copy from header (which have its license) and/or from web
(see https://www.microsoft.com/en-us/legal/intellectualproperty/copyright/default.aspx )
Not sure about the license. Looks like Mingw headers have public domain licensing.
For instance https://searchcode.com/codesearch/raw/11987244/ have a Microsoft disclaimer.
Maybe I'm too overcautious
> > > +struct QXLMonitorEscape {
>
> > > + QXLMonitorEscape(DEVMODE* dev_mode)
>
> > > + {
>
> > > + ZeroMemory(&_head, sizeof(_head));
>
> > > + _head.x = dev_mode->dmPosition.x;
>
> > > + _head.y = dev_mode->dmPosition.y;
>
> > > + _head.width = dev_mode->dmPelsWidth;
>
> > > + _head.height = dev_mode->dmPelsHeight;
>
> > > + }
>
> > > + QXLHead _head;
>
> > > +};
>
> > > +
>
> > > +struct QxlCustomEscapeObj : public QXLEscapeSetCustomDisplay {
>
> > > + QxlCustomEscapeObj(uint32_t bitsPerPel, uint32_t width, uint32_t
> > > height)
>
> > > + {
>
> > > + xres = width;
>
> > > + yres = height;
>
> > > + bpp = bitsPerPel;
>
> > > + }
>
> > > + QxlCustomEscapeObj() {};
>
> > > +};
>
> > > +
>
> > > +struct WDDMCustomDisplayEscape {
>
> > > + WDDMCustomDisplayEscape(DEVMODE* dev_mode)
>
> > > + {
>
> > > + _ioctl = QXL_ESCAPE_SET_CUSTOM_DISPLAY;
>
> > > + _custom.bpp = dev_mode->dmBitsPerPel;
>
> > > + _custom.xres = dev_mode->dmPelsWidth;
>
> > > + _custom.yres = dev_mode->dmPelsHeight;
>
> > > + }
>
> > > + int _ioctl;
>
> > > + QXLEscapeSetCustomDisplay _custom;
>
> > > +};
>
> > > +
>
> > > +struct WDDMMonitorConfigEscape {
>
> > > + WDDMMonitorConfigEscape(DisplayMode* mode)
>
> > > + {
>
> > > + _ioctl = QXL_ESCAPE_MONITOR_CONFIG;
>
> > > + _ head.id = _head.surface_id = 0;
>
> > > + _head.x = mode->get_pos_x();
>
> > > + _head.y = mode->get_pos_y();
>
> > > + _head.width = mode->get_width();
>
> > > + _head.height = mode->get_height();
>
> > > + }
>
> > > + int _ioctl;
>
> > > + QXLHead _head;
>
> > > +};
>
> > > +
>
> > > +DisplayConfig* DisplayConfig::create_config()
>
> > > +{
>
> > > + DisplayConfig* new_interface;
>
> > > + //Try to open a WDDM adapter.
>
> > > + new_interface = new WDDMInterface();
>
> > > + if(new_interface->type() == WDDM) {
>
> > > + return new_interface;
>
> > > + }
>
> > > + //If that failed so clean up and assume we have an XPDM driver
>
> > > + delete new_interface;
>
> > > +
>
> > > + new_interface = new XPDMInterface();
>
> > > + return new_interface;
>
> > > +}
>
> > > +
>
> > > +DisplayConfig::DisplayConfig()
>
> > > + : _driver_type(INVALID_DRIVER)
>
> > > + , _send_monitors_config(false)
>
> > > +{}
>
> > > +
>
> > > +bool XPDMInterface::is_attached(DISPLAY_DEVICE* dev_info)
>
> > > +{
>
> > > + return !!(dev_info->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP);
>
> > > +}
>
> > > +
>
> > > +bool XPDMInterface::set_monitor_state(LPCTSTR device_name, DEVMODE*
>
> > > dev_mode, MONITOR_STATE state)
>
> > > +{
>
> > > + dev_mode->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_POSITION;
>
> > > + if (state == MONITOR_ATTACHED) {
>
> > > + return true;
>
> > > + }
>
> > > +
>
> > > + LONG status = ChangeDisplaySettingsEx(device_name, dev_mode, NULL,
>
> > > CDS_UPDATEREGISTRY, NULL);
>
> > > + return (status == DISP_CHANGE_SUCCESSFUL);
>
> > > +}
>
> > > +
>
> > > +LONG XPDMInterface::update_display_settings()
>
> > > +{
>
> > > + return ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
>
> > > +}
>
> > > +
>
> > > +bool XPDMInterface::update_dev_mode_position(LPCTSTR device_name,
>
> > > + DEVMODE* dev_mode, LONG x, LONG
>
> > > y)
>
> > > +{
>
> > > + //Convert the position so that the primary is always at (0,0)
>
> > > + dev_mode->dmPosition.x = x;
>
> > > + dev_mode->dmPosition.y = y;
>
> > > + dev_mode->dmFields |= DM_POSITION;
>
> > > + vd_printf("%s: setting %S at (%lu, %lu)", __FUNCTION__, device_name,
>
> > > dev_mode->dmPosition.x,
>
> > > + dev_mode->dmPosition.y);
>
> > > +
>
> > > + LONG status = ChangeDisplaySettingsEx(device_name, dev_mode, NULL,
>
> > > + CDS_UPDATEREGISTRY | CDS_NORESET,
>
> > > NULL);
>
> > > + return (status == DISP_CHANGE_SUCCESSFUL);
>
> > > +}
>
> > > +
>
> > > +bool XPDMInterface::custom_display_escape(LPCTSTR device_name, DEVMODE*
>
> > > dev_mode)
>
> > > +{
>
> > > + LONG ret;
>
> > > + NTSTATUS Status (ERROR_SUCCESS);
>
> > > + HDC hdc = CreateDC(device_name, NULL, NULL, NULL);
>
> > > +
>
> > > + if (!hdc) {
>
> > > + ret = ChangeDisplaySettingsEx(device_name, dev_mode, NULL,
>
> > > CDS_UPDATEREGISTRY, NULL);
>
> > > + if (ret == DISP_CHANGE_BADMODE) {
>
> > > + // custom resolution might not be set yet, use known resolution
>
> > > + // FIXME: this causes client temporary resize... a
>
> > > + // solution would involve passing custom resolution before
>
> > > + // driver initialization, perhaps through registry
>
> > > + dev_mode->dmPelsWidth = 640;
>
> > > + dev_mode->dmPelsHeight = 480;
>
> > > + ret = ChangeDisplaySettingsEx(device_name, dev_mode, NULL,
>
> > > CDS_UPDATEREGISTRY, NULL);
>
> > > + }
>
> > > +
>
> > > + vd_printf("attach %ld", ret);
>
> > > + if (!(hdc = CreateDC(device_name, NULL, NULL, NULL))) {
>
> > > + vd_printf("%s: failed to create DC", __FUNCTION__);
>
> > > + return false;
>
> > > + }
>
> > > + }
>
> > > +
>
> > > + QxlCustomEscapeObj custom_escape(dev_mode->dmBitsPerPel,
>
> > > + dev_mode->dmPelsWidth,
>
> > > dev_mode->dmPelsHeight);
>
> > > +
>
> > > + int err = ExtEscape(hdc, QXL_ESCAPE_SET_CUSTOM_DISPLAY,
>
> > > + sizeof(QXLEscapeSetCustomDisplay), (LPCSTR) &custom_escape, 0,
>
> > > NULL);
>
> > > + if (err <= 0) {
>
> > > + vd_printf("%s: Can't set custom display, perhaps running with an
>
> > > older driver?",
>
> > > + __FUNCTION__);
>
> > > + }
>
> > > +
>
> > > + if (!find_best_mode(device_name, dev_mode)) {
>
> > > + Status = E_FAIL;
>
> > > + }
>
> > > +
>
> > > + DeleteDC(hdc);
>
> > > + return NT_SUCCESS(Status);
>
> > > +}
>
> > > +
>
> > > +bool XPDMInterface::update_monitor_config(LPCTSTR device_name,
> > > DisplayMode*
>
> > > mode,
>
> > > + DEVMODE* dev_mode)
>
> > > +{
>
> > > + if (!mode || !mode->get_attached()) {
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + QXLMonitorEscape monitor_config(dev_mode);
>
> > > + HDC hdc(CreateDC(device_name, NULL, NULL, NULL));
>
> > > + int err(0);
>
> > > +
>
> > > + if (!hdc || !_send_monitors_config) {
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + err = ExtEscape(hdc, QXL_ESCAPE_MONITOR_CONFIG, sizeof(QXLHead),
>
> > > + (LPCSTR) &monitor_config, 0, NULL);
>
> > > + if (err < 0) {
>
> > > + vd_printf("%s: %S can't update monitor config, may have old, old
>
> > > driver",
>
> > > + __FUNCTION__, device_name);
>
> > > + }
>
> > > + DeleteDC(hdc);
>
> > > + return (err >= 0);
>
> > > +}
>
> > > +
>
> > > +bool XPDMInterface::find_best_mode(LPCTSTR Device, DEVMODE* dev_mode)
>
> > > +{
>
> > > + DWORD closest_diff = -1;
>
> > > + DWORD best = -1;
>
> > > +
>
> > > + // force refresh mode table
>
> > > + DEVMODE test_dev_mode;
>
> > > + ZeroMemory(&test_dev_mode, sizeof(test_dev_mode));
>
> > > + test_dev_mode.dmSize = sizeof(DEVMODE);
>
> > > + EnumDisplaySettings(Device, 0xffffff, &test_dev_mode);
>
> > > +
>
> > > + //Find the closest size which will fit within the monitor
>
> > > + for (DWORD i = 0; EnumDisplaySettings(Device, i, &test_dev_mode); i++)
> > > {
>
> > > + if (dev_mode->dmPelsWidth > test_dev_mode.dmPelsWidth ||
>
> > > + dev_mode->dmPelsHeight > test_dev_mode.dmPelsHeight ||
>
> > > + dev_mode->dmBitsPerPel != test_dev_mode.dmBitsPerPel) {
>
> > > + continue;
>
> > > + }
>
> > > + DWORD wdiff = dev_mode->dmPelsWidth - test_dev_mode.dmPelsWidth;
>
> > > + DWORD hdiff = dev_mode->dmPelsHeight - test_dev_mode.dmPelsHeight;
>
> > > + DWORD diff = wdiff * wdiff + hdiff * hdiff;
>
> > > + if (diff < closest_diff) {
>
> > > + closest_diff = diff;
>
> > > + best = i;
>
> > > + }
>
> > > + }
>
> > > + vd_printf("%s: closest_diff at %lu best %lu", __FUNCTION__,
>
> > > closest_diff, best);
>
> > > + if (best == (DWORD) -1 || !EnumDisplaySettings(Device, best, dev_mode))
>
> > > {
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + //Change to the best fit
>
> > > + LONG status = ChangeDisplaySettingsEx(Device, dev_mode, NULL,
>
> > > + CDS_UPDATEREGISTRY | CDS_NORESET,
>
> > > NULL);
>
> > > + return NT_SUCCESS(status);
>
> > > +}
>
> > > +
>
> > > +WDDMInterface::WDDMInterface()
>
> > > + : _pfnOpen_adapter_hdc(NULL)
>
> > > + , _pfnClose_adapter(NULL)
>
> > > + , _pfnEscape(NULL)
>
> > > + , _pfnOpen_adapter_device_name(NULL)
>
> > > + , _pfnOpen_adapter_gdi_name(NULL)
>
> > > +{
>
> > > + _driver_type = INVALID_DRIVER;
>
> > > +
>
> > > + //Did the CCD load?
>
> > > + if (_ccd.error() == ERROR_NOT_SUPPORTED) {
>
> > > + return;
>
> > > + }
>
> > > +
>
> > > + //Can we find the D3D calls we need?
>
> > > + if (!init_d3d_api()) {
>
> > > + return;
>
> > > + }
>
> > > +
>
> > > + //Initialize CCD path stuff
>
> > > + if (!_ccd.query_display_config()) {
>
> > > + return;;
>
> > > + }
>
> > > + if (!_ccd.set_display_config()) {
>
> > > + return;
>
> > > + }
>
> > > + _driver_type = WDDM;
>
> > > +}
>
> > > +
>
> > > +WDDMInterface::~WDDMInterface()
>
> > > +{
>
> > > + if (_driver_type != WDDM) {
>
> > > + vd_printf("%s called with invalid driver type of %d", __FUNCTION__,
>
> > > _driver_type);
>
> > > + return;
>
> > > + }
>
> > > +}
>
> > > +
>
> > > +bool WDDMInterface::is_attached(DISPLAY_DEVICE* dev_info)
>
> > > +{
>
> > > + return _ccd.is_attached(dev_info->DeviceName);
>
> > > +}
>
> > > +
>
> > > +bool WDDMInterface::set_monitor_state(LPCTSTR device_name, DEVMODE*
>
> > > dev_mode, MONITOR_STATE state)
>
> > > +{
>
> > > + return _ccd.set_path_state(device_name, state);
>
> > > +}
>
> > > +
>
> > > +bool WDDMInterface::custom_display_escape(LPCTSTR device_name, DEVMODE*
>
> > > dev_mode)
>
> > > +{
>
> > > + DISPLAYCONFIG_MODE_INFO* mode = _ccd.get_active_mode(device_name,
>
> > > false);
>
> > > + if (!mode) {
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + //Don't bother if we are already set to the new resolution
>
> > > + if (mode->sourceMode.width == dev_mode->dmPelsWidth &&
>
> > > + mode->sourceMode.height == dev_mode->dmPelsHeight) {
>
> > > + return true;
>
> > > + }
>
> > > +
>
> > > + vd_printf("%s: updating %S resolution\n", __FUNCTION__, device_name);
>
> > > +
>
> > > + WDDMCustomDisplayEscape wddm_escape(dev_mode);
>
> > > + if (escape(device_name, &wddm_escape, sizeof(wddm_escape))) {
>
> > > + return _ccd.update_mode_size(device_name, dev_mode);
>
> > > + }
>
> > > +
>
> > > + vd_printf("%s: (%dx%d)", __FUNCTION__, mode->sourceMode.width,
>
> > > mode->sourceMode.height);
>
> > > + return false;
>
> > > +}
>
> > > +
>
> > > +bool WDDMInterface::update_monitor_config(LPCTSTR device_name,
> > > DisplayMode*
>
> > > display_mode,
>
> > > + DEVMODE* dev_mode)
>
> > > +{
>
> > > + if (!display_mode || !display_mode->get_attached()) {
>
> > > + return false;
>
> > > + }
>
> > > + DISPLAYCONFIG_MODE_INFO* mode = _ccd.get_active_mode(device_name,
>
> > > false);
>
> > > + if (!mode || !_send_monitors_config)
>
> > > + return false;
>
> > > +
>
> > > + WDDMMonitorConfigEscape wddm_escape(display_mode);
>
> > > + if (escape(device_name, &wddm_escape, sizeof(wddm_escape))) {
>
> > > + //Update the path position
>
> > > + return _ccd.update_mode_position(device_name, dev_mode);
>
> > > + }
>
> > > +
>
> > > + vd_printf("%s: %S failed", __FUNCTION__, device_name);
>
> > > + return false;
>
> > > +
>
> > > +}
>
> > > +
>
> > > +LONG WDDMInterface::update_display_settings()
>
> > > +{
>
> > > + //If we removed the primary monitor since the last call, we need to
>
> > > + //reorder the other monitors, making the leftmost one the primary
>
> > > + _ccd.verify_primary_position();
>
> > > +
>
> > > + if (!_ccd.set_display_config()) {
>
> > > + if (_ccd._error != ERROR_INVALID_PARAMETER) {
>
> > > + vd_printf("%s: set_display_config failed", __FUNCTION__);
>
> > > + } else {
>
> > > + vd_printf("%s: Invalid parameter!", __FUNCTION__);
>
> > > + _ccd.debug_print_config("After error");
>
> > > + }
>
> > > + }
>
> > > + return _ccd.error();
>
> > > +}
>
> > > +
>
> > > +void WDDMInterface::update_config_path()
>
> > > +{
>
> > > + _ccd.query_display_config();
>
> > > +}
>
> > > +
>
> > > +bool WDDMInterface::update_dev_mode_position(LPCTSTR device_name,
> > > DEVMODE*
>
> > > dev_mode,
>
> > > + LONG x, LONG y)
>
> > > +{
>
> > > + //Convert the position so that the primary is always at (0,0)
>
> > > + dev_mode->dmPosition.x = x;
>
> > > + dev_mode->dmPosition.y = y;
>
> > > + _ccd.update_mode_position(device_name, dev_mode);
>
> > > + return _ccd.update_mode_position(device_name, dev_mode);
>
> > > +}
>
> > > +
>
> > > +bool WDDMInterface::init_d3d_api()
>
> > > +{
>
> > > + HMODULE hModule = LoadLibrary(L"gdi32.dll");
>
> > > +
>
> > > + //Look for the gdi32 functions we need to perform driver escapes
>
> > > + if (!hModule) {
>
> > > + vd_printf("%s something wildly wrong as we can't open gdi32.dll",
>
> > > __FUNCTION__);
>
> > > + _driver_type = INVALID_DRIVER;
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + do {
>
> > > + _pfnClose_adapter = (PFND3DKMT_CLOSEADAPTER)
>
> > > + GetProcAddress(hModule, "D3DKMTCloseAdapter");
>
> > > + if (!_pfnClose_adapter) {
>
> > > + break;
>
> > > + }
>
> > > +
>
> > > + _pfnEscape = (PFND3DKMT_ESCAPE) GetProcAddress(hModule,
>
> > > "D3DKMTEscape");
>
> > > + if (!_pfnEscape) {
>
> > > + break;
>
> > > + }
>
> > > +
>
> > > + _pfnOpen_adapter_hdc = (PFND3DKMT_OPENADAPTERFROMHDC)
>
> > > + GetProcAddress(hModule, "D3DKMTOpenAdapterFromHdc");
>
> > > + if (!_pfnOpen_adapter_hdc) {
>
> > > + break;
>
> > > + }
>
> > > +
>
> > > + _pfnOpen_adapter_device_name = (PFND3DKMT_OPENADAPTERFROMDEVICENAME)
>
> > > + GetProcAddress(hModule, "D3DKMTOpenAdapterFromDeviceName");
>
> > > + if (!_pfnOpen_adapter_device_name) {
>
> > > + break;
>
> > > + }
>
> > > +
>
> > > + _pfnOpen_adapter_gdi_name =
>
> > > (PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)
>
> > > + GetProcAddress(hModule, "D3DKMTOpenAdapterFromGdiDisplayName");
>
> > > + if (!_pfnOpen_adapter_gdi_name) {
>
> > > + break;
>
> > > + }
>
> > > +
>
> > > + }
>
> > > + while(0);
>
> > > +
>
> > > + FreeLibrary(hModule);
>
> > > +
>
> > > + //Did we get them ?
>
> > > + if (!_pfnClose_adapter || !_pfnOpen_adapter_hdc || !_pfnEscape) {
>
> > > + return false;
>
> > > + }
>
> > > + _driver_type = WDDM;
>
> > > + return true;
>
> > > +}
>
> > > +
>
> > > +D3DKMT_HANDLE WDDMInterface::adapter_handle(LPCTSTR device_name)
>
> > > +{
>
> > > + D3DKMT_HANDLE hAdapter(0);
>
> > > +
>
> > > + //For some reason, unknown to me, this call will occasionally fail.
>
> > > + if ((hAdapter = handle_from_DC(device_name))) {
>
> > > + return hAdapter;
>
> > > + }
>
> > > + //So try other available methods.
>
> > > + if (_pfnOpen_adapter_device_name && (hAdapter =
>
> > > handle_from_device_name(device_name))) {
>
> > > + return hAdapter;
>
> > > + }
>
> > > + //One last chance to open this guy
>
> > > + if (_pfnOpen_adapter_gdi_name) {
>
> > > + hAdapter = handle_from_GDI_name(device_name);
>
> > > + }
>
> > > +
>
> > > + if (!hAdapter) {
>
> > > + vd_printf("%s: failed to open adapter %S", __FUNCTION__,
>
> > > device_name);
>
> > > + }
>
> > > +
>
> > > + return hAdapter;
>
> > > +}
>
> > > +
>
> > > +D3DKMT_HANDLE WDDMInterface::handle_from_DC(LPCTSTR adapter_name)
>
> > > +{
>
> > > + NTSTATUS status;
>
> > > + D3DKMT_OPENADAPTERFROMHDC open_data;
>
> > > + HDC hDc(CreateDC(adapter_name, NULL, NULL, NULL));
>
> > > +
>
> > > + if (!hDc) {
>
> > > + vd_printf("%s: %S CreateDC failed with %lu", __FUNCTION__,
>
> > > adapter_name, GetLastError());
>
> > > + return 0;
>
> > > + }
>
> > > +
>
> > > + ZeroMemory(&open_data, sizeof(D3DKMT_OPENADAPTERFROMHDC));
>
> > > + open_data.hDc = hDc;
>
> > > +
>
> > > + if (!NT_SUCCESS(status = _pfnOpen_adapter_hdc(&open_data))) {
>
> > > + vd_printf("%s: %S open adapter from hdc failed with %lu",
>
> > > __FUNCTION__, adapter_name,
>
> > > + status);
>
> > > + open_data.hAdapter = 0;
>
> > > + }
>
> > > +
>
> > > + DeleteDC(hDc);
>
> > > + return open_data.hAdapter;
>
> > > +}
>
> > > +
>
> > > +D3DKMT_HANDLE WDDMInterface::handle_from_device_name(LPCTSTR
> > > adapter_name)
>
> > > +{
>
> > > + D3DKMT_OPENADAPTERFROMDEVICENAME display_name_data;
>
> > > + NTSTATUS status;
>
> > > +
>
> > > + ZeroMemory(&display_name_data, sizeof(display_name_data));
>
> > > + display_name_data.pDeviceName = adapter_name;
>
> > > +
>
> > > + if (NT_SUCCESS(status =
>
> > > _pfnOpen_adapter_device_name(&display_name_data))) {
>
> > > + return display_name_data.hAdapter;
>
> > > + }
>
> > > +
>
> > > + vd_printf("%s %S failed with 0x%lx", __FUNCTION__, adapter_name,
>
> > > status);
>
> > > + return 0;
>
> > > +}
>
> > > +
>
> > > +D3DKMT_HANDLE WDDMInterface::handle_from_GDI_name(LPCTSTR adapter_name)
>
> > > +{
>
> > > + D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME gdi_display_name;
>
> > > + NTSTATUS status;
>
> > > +
>
> > > + ZeroMemory(&gdi_display_name, sizeof(gdi_display_name));
>
> > > + memcpy((void *) gdi_display_name.DeviceName, adapter_name,
>
> > > sizeof(TCHAR)* CCHDEVICENAME);
>
> > > +
>
> > > + if (NT_SUCCESS(status = _pfnOpen_adapter_gdi_name(&gdi_display_name)))
> > > {
>
> > > + return gdi_display_name.hAdapter;
>
> > > + }
>
> > > +
>
> > > + vd_printf("%s: %S aurrrgghh nothing works..error is 0x%lx",
>
> > > __FUNCTION__, adapter_name,
>
> > > + status);
>
> > > + return 0;
>
> > > +}
>
> > > +
>
> > > +void WDDMInterface::close_adapter(D3DKMT_HANDLE handle)
>
> > > +{
>
> > > + D3DKMT_CLOSEADAPTER closeData;
>
> > > + if (handle) {
>
> > > + closeData.hAdapter = handle;
>
> > > + _pfnClose_adapter(&closeData);
>
> > > + }
>
> > > +}
>
> > > +
>
> > > +bool WDDMInterface::escape(LPCTSTR device_name, void* data, UINT
> > > size_data)
>
> > > +{
>
> > > + D3DKMT_ESCAPE escapeData;
>
> > > + NTSTATUS status;
>
> > > + D3DKMT_HANDLE hAdapter(0);
>
> > > +
>
> > > + if (!(hAdapter = adapter_handle(device_name)))
>
> > > + return false;
>
> > > +
>
> > > + escapeData.hAdapter = hAdapter;
>
> > > + escapeData.hDevice = 0;
>
> > > + escapeData.hContext = 0;
>
> > > + escapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
>
> > > + escapeData.Flags.Value = 0;
>
> > > + escapeData.pPrivateDriverData = data;
>
> > > + escapeData.PrivateDriverDataSize = size_data;
>
> > > +
>
> > > + status = _pfnEscape(&escapeData);
>
> > > +
>
> > > + if (!NT_SUCCESS(status)) {
>
> > > + vd_printf("%s: this should never happen. Status is 0x%lx",
>
> > > __FUNCTION__, status);
>
> > > + _driver_type = INVALID_DRIVER;
>
> > > + }
>
> > > +
>
> > > + //Close the handle to this device
>
> > > + close_adapter(hAdapter);
>
> > > + return NT_SUCCESS(status);
>
> > > +}
>
> > > +
>
> > > +CCD::CCD()
>
> > > + :_NumPathElements(0)
>
> > > + ,_NumModeElements(0)
>
> > > + ,_pPathInfo(NULL)
>
> > > + ,_pModeInfo(NULL)
>
> > > + ,_pfnGetDeviceInfo(NULL)
>
> > > + ,_pfnGetDisplayConfigBufferSizes(NULL)
>
> > > + ,_pfnQueryDisplayConfig(NULL)
>
> > > + ,_pfnSetDisplayConfig(NULL)
>
> > > + ,_error(0)
>
> > > + ,_primary_detached(false)
>
> > > + ,_path_state(PATH_UPDATED)
>
> > > +{
>
> > > + if (load_api()) {
>
> > > + get_config_buffers();
>
> > > + }
>
> > > +}
>
> > > +
>
> > > +CCD::~CCD()
>
> > > +{
>
> > > + free_config_buffers();
>
> > > +}
>
> > > +
>
> > > +bool CCD::query_display_config()
>
> > > +{
>
> > > + LONG query_error(ERROR_SUCCESS);
>
> > > +
>
> > > + //Until we get it or error != ERROR_INSUFFICIENT_BUFFER
>
> > > + do {
>
> > > + query_error = _pfnQueryDisplayConfig(QDC_ALL_PATHS,
>
> > > &_NumPathElements, _pPathInfo,
>
> > > + &_NumModeElements, _pModeInfo, NULL);
>
> > > +
>
> > > + // if ERROR_INSUFFICIENT_BUFFER need to retry QueryDisplayConfig
>
> > > + // to get a new set of config buffers
>
> > > + //(see
>
> > > https://msdn.microsoft.com/en-us/library/windows/hardware/ff569215(v=vs.85).aspx
>
> > > )
>
> > > + if (query_error) {
>
> > > + if (query_error == ERROR_INSUFFICIENT_BUFFER) {
>
> > > + free_config_buffers();
>
> > > + if (!get_config_buffers())
>
> > > + return false;
>
> > > + } else {
>
> > > + _error = query_error;
>
> > > + vd_printf("%s failed QueryDisplayConfig with 0x%lx",
>
> > > __FUNCTION__, _error);
>
> > > + return false;
>
> > > + }
>
> > > + }
>
> > > + } while(query_error);
>
> > > + _path_state = PATH_CURRENT;
>
> > > + return true;
>
> > > +}
>
> > > +
>
> > > +DISPLAYCONFIG_MODE_INFO* CCD::get_active_mode(LPCTSTR device_name, bool
>
> > > return_on_error)
>
> > > +{
>
> > > + DISPLAYCONFIG_PATH_INFO* active_path;
>
> > > +
>
> > > + active_path = get_device_path(device_name, true);
>
> > > +
>
> > > + if (!active_path ) {
>
> > > + vd_printf("%s:%S failed", __FUNCTION__, device_name);
>
> > > + return NULL;
>
> > > + }
>
> > > + return &_pModeInfo[active_path->sourceInfo.modeInfoIdx];
>
> > > +}
>
> > > +
>
> > > +bool CCD::set_display_config() {
>
> > > +
>
> > > + debug_print_config("Before SetDisplayConfig");
>
> > > +
>
> > > + if (_path_state == PATH_CURRENT) {
>
> > > + vd_printf("%s: path states says nothing changed", __FUNCTION__);
>
> > > + return true;
>
> > > + }
>
> > > +
>
> > > + if (!(_error = _pfnSetDisplayConfig(_NumPathElements, _pPathInfo,
>
> > > + _NumModeElements, _pModeInfo,
>
> > > + SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG |
>
> > > SDC_FORCE_MODE_ENUMERATION))) {
>
> > > + return true;
>
> > > + }
>
> > > +
>
> > > + vd_printf("%s failed SetDisplayConfig with 0x%lx", __FUNCTION__,
>
> > > _error);
>
> > > + debug_print_config("After failed SetDisplayConfig");
>
> > > + return false;
>
> > > +}
>
> > > +
>
> > > +DISPLAYCONFIG_PATH_INFO* CCD::get_device_path(LPCTSTR device_name, bool
>
> > > bActive)
>
> > > +{
>
> > > + //Search for device's active path
>
> > > + for (UINT32 i = 0; i < _NumPathElements; i++) {
>
> > > + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i];
>
> > > +
>
> > > + //if bActive, return only paths that are currently active
>
> > > + if (bActive && !is_active_path(path_info))
>
> > > + continue;
>
> > > + if (!is_device_path(device_name, path_info))
>
> > > + continue;
>
> > > + return path_info;
>
> > > + }
>
> > > + _error = ERROR_GEN_FAILURE;
>
> > > + return NULL;
>
> > > +}
>
> > > +
>
> > > +void CCD::debug_print_config(const char* prefix)
>
> > > +{
>
> > > + TCHAR dev_name[CCHDEVICENAME];
>
> > > + for (UINT32 i = 0; i < _NumPathElements; i++) {
>
> > > + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i];
>
> > > + if (!(path_info->flags & DISPLAYCONFIG_PATH_ACTIVE))
>
> > > + continue;
>
> > > + get_device_name_config(path_info, dev_name);
>
> > > +
>
> > > + if (path_info->sourceInfo.modeInfoIdx ==
>
> > > DISPLAYCONFIG_PATH_MODE_IDX_INVALID) {
>
> > > + vd_printf("%s: %S [%s] This path is active but has invalid mode
>
> > > set.", __FUNCTION__,
>
> > > + dev_name, prefix);
>
> > > + continue;
>
> > > + }
>
> > > + DISPLAYCONFIG_MODE_INFO* mode =
>
> > > &_pModeInfo[path_info->sourceInfo.modeInfoIdx];
>
> > > + vd_printf("%s: %S [%s] (%ld,%ld) (%ux%u).", __FUNCTION__, dev_name,
>
> > > prefix,
>
> > > + mode->sourceMode.position.x, mode->sourceMode.position.y,
>
> > > + mode->sourceMode.width, mode->sourceMode.height);
>
> > > + }
>
> > > +}
>
> > > +
>
> > > +bool CCD::load_api()
>
> > > +{
>
> > > + HMODULE hModule = LoadLibrary(L"user32.dll");
>
> > > + if(!hModule) {
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + bool bFound_all(false);
>
> > > + do {
>
> > > + if (!(_pfnGetDeviceInfo = (PDISPLAYCONFIG_GETDEVICEINFO)
>
> > > + GetProcAddress(hModule, "DisplayConfigGetDeviceInfo"))) {
>
> > > + break;
>
> > > + }
>
> > > +
>
> > > + if (!(_pfnGetDisplayConfigBufferSizes =
>
> > > (PGETDISPLAYCONFIG_BUFFERSIZES)
>
> > > + GetProcAddress(hModule, "GetDisplayConfigBufferSizes"))) {
>
> > > + break;
>
> > > + }
>
> > > +
>
> > > + if (!(_pfnQueryDisplayConfig = (PQUERYDISPLAYCONFIG)
>
> > > + GetProcAddress(hModule, "QueryDisplayConfig"))) {
>
> > > + break;
>
> > > + }
>
> > > +
>
> > > + if (!(_pfnSetDisplayConfig = (PSETDISPLAYCONFIG)
>
> > > + GetProcAddress(hModule, "SetDisplayConfig"))) {
>
> > > + break;
>
> > > + }
>
> > > + bFound_all = true;
>
> > > + }
>
> > > + while(0);
>
> > > +
>
> > > + FreeLibrary(hModule);
>
> > > + return bFound_all;
>
> > > +}
>
> > > +
>
> > > +bool CCD::get_config_buffers()
>
> > > +{
>
> > > + //Get Config Buffer Sizes
>
> > > + free_config_buffers();
>
> > > + _error = _pfnGetDisplayConfigBufferSizes(QDC_ALL_PATHS,
>
> > > &_NumPathElements,
>
> > > + &_NumModeElements);
>
> > > + if (_error) {
>
> > > + vd_printf("%s: GetDisplayConfigBufferSizes failed with 0x%lx",
>
> > > __FUNCTION__, _error);
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + //Allocate arrays
>
> > > + _pPathInfo = ((DISPLAYCONFIG_PATH_INFO*)
>
> > > malloc(sizeof(DISPLAYCONFIG_PATH_INFO) * _NumPathElements));
>
> > > + _pModeInfo = ((DISPLAYCONFIG_MODE_INFO*)
>
> > > malloc(sizeof(DISPLAYCONFIG_MODE_INFO) * _NumModeElements));
>
> > > +
>
> > > + if (!_pPathInfo || !_pModeInfo) {
>
> > > + vd_printf("%s OOM ", __FUNCTION__);
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + ///clear the above arrays
>
> > > + ZeroMemory(_pPathInfo, sizeof(DISPLAYCONFIG_PATH_INFO) *
>
> > > _NumPathElements);
>
> > > + ZeroMemory(_pModeInfo, sizeof(DISPLAYCONFIG_MODE_INFO) *
>
> > > _NumModeElements);
>
> > > + return true;
>
> > > +}
>
> > > +
>
> > > +void CCD::free_config_buffers()
>
> > > +{
>
> > > + if (_pModeInfo) {
>
> > > + free(_pModeInfo);
>
> > > + _pModeInfo = NULL;
>
> > > + }
>
> > > + if (_pPathInfo) {
>
> > > + free(_pPathInfo);
>
> > > + _pPathInfo = NULL;
>
> > > + }
>
> > > + _NumModeElements = _NumPathElements = 0;
>
> > > +}
>
> > > +
>
> > > +bool CCD::get_device_name_config(DISPLAYCONFIG_PATH_INFO* path, LPCTSTR
>
> > > dev_name)
>
> > > +{
>
> > > + DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name;
>
> > > + source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
>
> > > + source_name.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
>
> > > + source_name.header.adapterId = path->sourceInfo.adapterId;
>
> > > + source_name.header.id = path->sourceInfo.id;
>
> > > +
>
> > > + _error = _pfnGetDeviceInfo(&source_name.header);
>
> > > + if (_error) {
>
> > > + vd_printf("%s DisplayConfigGetDeviceInfo failed with %lu",
>
> > > __FUNCTION__, _error);
>
> > > + return false;
>
> > > + }
>
> > > + memcpy((void *)dev_name, source_name.viewGdiDeviceName, CCHDEVICENAME*
>
> > > sizeof(TCHAR));
>
> > > + return true;
>
> > > +}
>
> > > +
>
> > > +bool CCD::is_device_path(LPCTSTR device_name, DISPLAYCONFIG_PATH_INFO*
> > > path)
>
> > > +{
>
> > > + //Does this path belong to device_name?
>
> > > + TCHAR dev_name[CCHDEVICENAME];
>
> > > + if (!get_device_name_config(path, dev_name)) {
>
> > > + return false;
>
> > > + }
>
> > > + if (_tcscmp(dev_name, device_name)) {
>
> > > + return false;
>
> > > + }
>
> > > + return true;
>
> > > +}
>
> > > +
>
> > > +// If we have detached the primary monitor, then we need to reset the
>
> > > positions of the remaining
>
> > > +// monitors to insure that at least one is positioned at (0,0)
>
> > > +bool CCD::verify_primary_position()
>
> > > +{
>
> > > + LONG leftmost_x(0);
>
> > > + if (!_primary_detached) {
>
> > > + return true;
>
> > > + }
>
> > > + _primary_detached = false;
>
> > > +
>
> > > + for (UINT32 i = 0; i < _NumPathElements; i++) {
>
> > > + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i];
>
> > > + if (!(path_info->flags & DISPLAYCONFIG_PATH_ACTIVE))
>
> > > + continue;
>
> > > +
>
> > > + DISPLAYCONFIG_MODE_INFO* mode =
>
> > > &_pModeInfo[path_info->sourceInfo.modeInfoIdx];
>
> > > + if (leftmost_x > mode->sourceMode.position.x) {
>
> > > + leftmost_x = mode->sourceMode.position.x;
>
> > > + }
>
> > > + }
>
> > > +
>
> > > + if (leftmost_x == 0) {
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + for (UINT32 i = 0; i < _NumPathElements; i++) {
>
> > > + DISPLAYCONFIG_PATH_INFO* path_info = &_pPathInfo[i];
>
> > > + if ((!(path_info->flags & DISPLAYCONFIG_PATH_ACTIVE)))
>
> > > + continue;
>
> > > + DISPLAYCONFIG_MODE_INFO* mode =
>
> > > &_pModeInfo[path_info->sourceInfo.modeInfoIdx];
>
> > > + vd_printf("%s: setting mode x to %lu", __FUNCTION__,
>
> > > mode->sourceMode.position.x);
>
> > > + mode->sourceMode.position.x -= leftmost_x;
>
> > > + }
>
> > > + _path_state = PATH_UPDATED;
>
> > > + return true;
>
> > > +}
>
> > > +
>
> > > +bool CCD::update_mode_position(LPCTSTR device_name, DEVMODE* dev_mode)
>
> > > +{
>
> > > + DISPLAYCONFIG_MODE_INFO* mode = get_active_mode(device_name, false);
>
> > > + if (!mode)
>
> > > + return false;
>
> > > +
>
> > > + mode->sourceMode.position.x = dev_mode->dmPosition.x;
>
> > > + mode->sourceMode.position.y = dev_mode->dmPosition.y;
>
> > > + vd_printf("%s: %S updated path mode to (%lu, %lu) - (%u x%u)",
>
> > > __FUNCTION__,
>
> > > + device_name,
>
> > > + mode->sourceMode.position.x, mode->sourceMode.position.y,
>
> > > + mode->sourceMode.width, mode->sourceMode.height);
>
> > > + _path_state = PATH_UPDATED;
>
> > > + return true;
>
> > > +
>
> > > +}
>
> > > +
>
> > > +bool CCD::update_mode_size(LPCTSTR device_name, DEVMODE* dev_mode)
>
> > > +{
>
> > > + DISPLAYCONFIG_MODE_INFO* mode = get_active_mode(device_name, false);
>
> > > + if (!mode) {
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + mode->sourceMode.width = dev_mode->dmPelsWidth;
>
> > > + mode->sourceMode.height = dev_mode->dmPelsHeight;
>
> > > + vd_printf("%s: %S updated path mode to (%lu, %lu - (%u x %u)",
>
> > > __FUNCTION__,
>
> > > + device_name,
>
> > > + mode->sourceMode.position.x, mode->sourceMode.position.y,
>
> > > + mode->sourceMode.width, mode->sourceMode.height);
>
> > > + _path_state = PATH_UPDATED;
>
> > > + return true;
>
> > > +}
>
> > > +
>
> > > +void CCD::update_detached_primary_state(LPCTSTR device_name,
>
> > > DISPLAYCONFIG_PATH_INFO * path_info)
>
> > > +{
>
> > > + DISPLAYCONFIG_MODE_INFO* mode(get_active_mode(device_name, false));
>
> > > +
>
> > > + //will need to reset monitor positions if primary detached
>
> > > + path_info->flags = path_info->flags & ~DISPLAYCONFIG_PATH_ACTIVE;
>
> > > + if (!mode|| mode->sourceMode.position.x != 0 ||
>
> > > mode->sourceMode.position.y != 0) {
>
> > > + return ;
>
> > > + }
>
> > > + _primary_detached = true;
>
> > > +}
>
> > > +
>
> > > +bool CCD::set_path_state(LPCTSTR device_name, MONITOR_STATE new_state)
>
> > > +{
>
> > > + DISPLAYCONFIG_PATH_INFO* path(get_device_path(device_name, false));
>
> > > + MONITOR_STATE current_path_state(MONITOR_DETACHED);
>
> > > +
>
> > > + if (path && (path->flags & DISPLAYCONFIG_PATH_ACTIVE)) {
>
> > > + current_path_state = MONITOR_ATTACHED;
>
> > > + }
>
> > > +
>
> > > + //If state didn't change, nothing to do
>
> > > + if (current_path_state == new_state ) {
>
> > > + return true;
>
> > > + }
>
> > > +
>
> > > + if (!path) {
>
> > > + return false;
>
> > > + }
>
> > > +
>
> > > + _path_state = PATH_UPDATED;
>
> > > + if (new_state == MONITOR_DETACHED) {
>
> > > + update_detached_primary_state(device_name, path);
>
> > > + } else {
>
> > > + path->flags = path->flags | DISPLAYCONFIG_PATH_ACTIVE;
>
> > > + set_display_config();
>
> > > + }
>
> > > + return true;
>
> > > +}
>
> > > +
>
> > > +bool CCD::is_attached(LPCTSTR device_name)
>
> > > +{
>
> > > + DISPLAYCONFIG_PATH_INFO* path(get_device_path(device_name, false));
>
> > > + if (!path) {
>
> > > + return false;
>
> > > + }
>
> > > + return (path->flags & DISPLAYCONFIG_PATH_ACTIVE);
>
> > > +}
>
> > > +
>
> > > +bool CCD::is_active_path(DISPLAYCONFIG_PATH_INFO * path)
>
> > > +{
>
> > > + if (!path || !(path->flags & DISPLAYCONFIG_PATH_ACTIVE) ||
>
> > > + (path->sourceInfo.modeInfoIdx ==
>
> > > DISPLAYCONFIG_PATH_MODE_IDX_INVALID)) {
>
> > > + return false;
>
> > > + }
>
> > > + return true;
>
> > > +}
>
> > > diff --git a/vdagent/display_configuration.h
>
> > > b/vdagent/display_configuration.h
>
> > > new file mode 100755
>
> > > index 0000000..870a28d
>
> > > --- /dev/null
>
> > > +++ b/vdagent/display_configuration.h
>
> > > @@ -0,0 +1,191 @@
>
> > > +/*
>
> > > +Copyright (C) 2015 Red Hat, Inc.
>
> > > +
>
> > > +This program is free software; you can redistribute it and/or
>
> > > +modify it under the terms of the GNU General Public License as
>
> > > +published by the Free Software Foundation; either version 2 of
>
> > > +the License, or (at your option) any later version.
>
> > > +
>
> > > +This program is distributed in the hope that it will be useful,
>
> > > +but WITHOUT ANY WARRANTY; without even the implied warranty of
>
> > > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>
> > > +GNU General Public License for more details.
>
> > > +
>
> > > +You should have received a copy of the GNU General Public License
>
> > > +along with this program. If not, see < http://www.gnu.org/licenses/ >.
>
> > > +*/
>
> > > +#ifndef _H_DISPLAY_CONFIGURATION
>
> > > +#define _H_DISPLAY_CONFIGURATION
>
> > > +
>
> > > +#include <spice/qxl_windows.h>
>
> > > +#include <spice/qxl_dev.h>
>
> > > +#include "desktop_layout.h"
>
> > > +#include "vdlog.h"
>
> > > +
>
> > > +enum DRIVER_TYPE {
>
> > > + XPDM,
>
> > > + WDDM,
>
> > > + INVALID_DRIVER,
>
> > > +};
>
> > > +
>
> > > +enum MONITOR_STATE {
>
> > > + MONITOR_DETACHED,
>
> > > + MONITOR_ATTACHED,
>
> > > +};
>
> > > +
>
> > > +enum PATH_STATE {
>
> > > + PATH_UPDATED,
>
> > > + PATH_CURRENT,
>
> > > +};
>
> > > +
>
> > > +enum DISPLAYCONFIG_TOPOLOGY_ID {};
>
> > > +
>
> > > +struct DISPLAYCONFIG_DEVICE_INFO_HEADER;
>
> > > +struct DISPLAYCONFIG_MODE_INFO;
>
> > > +struct DISPLAYCONFIG_PATH_INFO;
>
> > > +
>
> > > +//Makes calls into the CCD API for getting/setting display settings on
> > > WDDM
>
> > > drivers
>
> > > +//Use is exclusive to wddm display config class
>
> > > +
>
> > > +typedef LONG(APIENTRY*
>
> > > PDISPLAYCONFIG_GETDEVICEINFO)(DISPLAYCONFIG_DEVICE_INFO_HEADER*);
>
> > > +typedef LONG(APIENTRY* PGETDISPLAYCONFIG_BUFFERSIZES)(UINT32, UINT32*,
>
> > > UINT32*);
>
> > > +typedef LONG(APIENTRY* PQUERYDISPLAYCONFIG)(UINT32, UINT32*,
>
> > > DISPLAYCONFIG_PATH_INFO*, UINT32*,
>
> > > + DISPLAYCONFIG_MODE_INFO*,
>
> > > DISPLAYCONFIG_TOPOLOGY_ID*);
>
> > > +typedef LONG(APIENTRY* PSETDISPLAYCONFIG)(UINT32,
> > > DISPLAYCONFIG_PATH_INFO*,
>
> > > UINT32,
>
> > > + DISPLAYCONFIG_MODE_INFO*, UINT32);
>
> > > +
>
> > > +class CCD {
>
> > > +protected:
>
> > This should be public, protected is used for inheritance.
>
> The class "WDDMInterface" has an instance of the "CCD" class, The constructor
> and destructor of the
> "CCD" class are both protected, this enables the friend class "WDDMInterface"
> to
> create and destroy CCD objects.
I know what friend does. Still I think this usage is wrong. I prefer the Javer's CDDLibrary style.
There is no reason to bound CCD to WDDMInterface and there are other better way to do it like a nested
private class instead.
> > > + CCD();
>
> > > + ~CCD();
>
> > > +
>
> > > + bool query_display_config();
>
> > > + bool set_display_config();
>
> > > + bool update_mode_position(LPCTSTR device_name, DEVMODE* dev_mode);
>
> > > + bool update_mode_size(LPCTSTR DeviceNmae, DEVMODE* dev_mode);
>
> > > + void update_detached_primary_state(LPCTSTR device_name,
>
> > > DISPLAYCONFIG_PATH_INFO * path_info);
>
> > > + bool set_path_state(LPCTSTR device_name, MONITOR_STATE state);
>
> > > + bool is_attached(LPCTSTR device_name);
>
> > > + bool is_active_path(DISPLAYCONFIG_PATH_INFO * path);
>
> > > + LONG error() { return _error; }
>
> > > +
>
> > > +private:
>
> > > + bool load_api();
>
> > > + bool get_config_buffers();
>
> > > + void free_config_buffers();
>
> > > + bool verify_primary_position();
>
> > > + bool is_device_path(LPCTSTR device_name, DISPLAYCONFIG_PATH_INFO*
> > > path);
>
> > > + DISPLAYCONFIG_MODE_INFO* get_active_mode(LPCTSTR device_name, bool
>
> > > return_on_error);
>
> > > + DISPLAYCONFIG_PATH_INFO* get_device_path(LPCTSTR device_name, bool
>
> > > bActive);
>
> > > + bool get_device_name_config(DISPLAYCONFIG_PATH_INFO* path, LPCTSTR
>
> > > dev_name);
>
> > > + void debug_print_config(const char* prefix = NULL);
>
> > > +
>
> > > +private:
>
> > > + //CCD API stuff
>
> > > + UINT32 _NumPathElements;
>
> > > + UINT32 _NumModeElements;
>
> > > + DISPLAYCONFIG_PATH_INFO* _pPathInfo;
>
> > > + DISPLAYCONFIG_MODE_INFO* _pModeInfo;
>
> > > +
>
> > > + //CCD API function pointers
>
> > > + PDISPLAYCONFIG_GETDEVICEINFO _pfnGetDeviceInfo;
>
> > > + PGETDISPLAYCONFIG_BUFFERSIZES _pfnGetDisplayConfigBufferSizes;
>
> > > + PQUERYDISPLAYCONFIG _pfnQueryDisplayConfig;
>
> > > + PSETDISPLAYCONFIG _pfnSetDisplayConfig;
>
> > > +
>
> > > + LONG _error;
>
> > > + bool _primary_detached;
>
> > > + PATH_STATE _path_state;
>
> > > + friend class WDDMInterface;
>
> > There should be no reason for friend.
>
> > > +};
>
> > > +
>
> > > +class DisplayMode;
>
> > > +
>
> > > +//Class provides interface to get/set display configurations
>
> > > +class DisplayConfig {
>
> > > +public:
>
> > > + static DisplayConfig* create_config();
>
> > > + DisplayConfig();;
>
> > typo (;;).
>
> > > + virtual ~DisplayConfig() {};
>
> > > +
>
> > > + virtual bool is_attached(DISPLAY_DEVICE* dev_info) = 0;
>
> > > + virtual bool custom_display_escape(LPCTSTR device, DEVMODE* mode) = 0;
>
> > > + virtual bool update_monitor_config(LPCTSTR device, DisplayMode* mode,
>
> > > DEVMODE* dev_mode) = 0;
>
> > > + virtual bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode,
>
> > > MONITOR_STATE state) = 0;
>
> > > + virtual LONG update_display_settings() = 0;
>
> > > + virtual bool update_dev_mode_position(LPCTSTR dev_name, DEVMODE*
>
> > > dev_mode, LONG x, LONG y) = 0;
>
> > > + DRIVER_TYPE type() { return _driver_type; };
>
> > const and actually quite a bad design, I would remove this member
>
> > entirely.
>
> > > + void set_monitors_config(bool flag) { _send_monitors_config = flag; }
>
> > > + virtual void update_config_path() {};
>
> > > +
>
> > > +protected:
>
> > > + DRIVER_TYPE _driver_type;
>
> > also I would remove this field. Would be much better to have a
>
> > WDDMInterface::init that returns true/false.
>
> > Actually WDDMInterface is quite a bad name for an implementation.
>
> > > + bool _send_monitors_config;
>
> > > +};
>
> > > +
>
> > > +//DisplayConfig implementation for guest with XPDM graphics drivers
>
> > > +class XPDMInterface : public DisplayConfig {
>
> > > +public:
>
> > > + XPDMInterface() :DisplayConfig() { _driver_type = XPDM; };
>
> > > + ~XPDMInterface() {}
>
> > > + bool is_attached(DISPLAY_DEVICE* dev_info);;
>
> > typo (;;).
>
> > > + bool custom_display_escape(LPCTSTR device_name, DEVMODE* dev_mode);
>
> > > + bool update_monitor_config(LPCTSTR device_name, DisplayMode* mode,
>
> > > DEVMODE* dev_mode);
>
> > > + bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode,
>
> > > MONITOR_STATE state);
>
> > > + LONG update_display_settings();
>
> > > + bool update_dev_mode_position(LPCTSTR device_name, DEVMODE * dev_mode,
>
> > > LONG x, LONG y);
>
> > > +
>
> > > +private:
>
> > > + bool find_best_mode(LPCTSTR Device, DEVMODE* dev_mode);
>
> > > +};
>
> > > +
>
> > > +//DisplayConfig implementation for guest with WDDM graphics drivers
>
> > > +typedef UINT D3DKMT_HANDLE;
>
> > > +
>
> > > +struct D3DKMT_ESCAPE;
>
> > > +struct D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME;
>
> > > +struct D3DKMT_OPENADAPTERFROMDEVICENAME;
>
> > > +struct D3DKMT_CLOSEADAPTER;
>
> > > +struct D3DKMT_OPENADAPTERFROMHDC;
>
> > > +
>
> > > +typedef NTSTATUS(APIENTRY* PFND3DKMT_ESCAPE)(CONST D3DKMT_ESCAPE*);
>
> > > +typedef NTSTATUS(APIENTRY*
>
> > > PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME*);
>
> > > +typedef NTSTATUS(APIENTRY*
>
> > > PFND3DKMT_OPENADAPTERFROMDEVICENAME)(D3DKMT_OPENADAPTERFROMDEVICENAME*);
>
> > > +typedef NTSTATUS(APIENTRY*
> > > PFND3DKMT_CLOSEADAPTER)(D3DKMT_CLOSEADAPTER*);
>
> > > +typedef NTSTATUS(APIENTRY*
>
> > > PFND3DKMT_OPENADAPTERFROMHDC)(D3DKMT_OPENADAPTERFROMHDC*);
>
> > > +
>
> > > +class WDDMInterface : public DisplayConfig {
>
> > > +public:
>
> > > + WDDMInterface();
>
> > > + ~WDDMInterface();
>
> > > + bool is_attached(DISPLAY_DEVICE* dev_info);
>
> > > + bool set_monitor_state(LPCTSTR device_name, DEVMODE* dev_mode,
>
> > > MONITOR_STATE state);
>
> > > + LONG update_display_settings();
>
> > > + bool custom_display_escape(LPCTSTR device_name, DEVMODE* dev_mode);
>
> > > + bool update_monitor_config(LPCTSTR device_name, DisplayMode* mode,
>
> > > DEVMODE* dev_mode);
>
> > > + bool update_dev_mode_position(LPCTSTR device_name, DEVMODE * dev_mode,
>
> > > LONG x, LONG y);
>
> > > + void update_config_path();
>
> > > +
>
> > > +private:
>
> > > + bool init_d3d_api();
>
> > > + D3DKMT_HANDLE adapter_handle(LPCTSTR device_name);
>
> > > + D3DKMT_HANDLE handle_from_DC(LPCTSTR adapter_name);
>
> > > + D3DKMT_HANDLE handle_from_device_name(LPCTSTR adapter_name);
>
> > > + D3DKMT_HANDLE handle_from_GDI_name(LPCTSTR adapter_name);
>
> > > +
>
> > > + void close_adapter(D3DKMT_HANDLE handle);
>
> > > + bool escape(LPCTSTR device_name, void* data, UINT sizeData);
>
> > > +
>
> > > +private:
>
> > > + //GDI Function pointers
>
> > > + PFND3DKMT_OPENADAPTERFROMHDC _pfnOpen_adapter_hdc;
>
> > > + PFND3DKMT_CLOSEADAPTER _pfnClose_adapter;
>
> > > + PFND3DKMT_ESCAPE _pfnEscape;
>
> > > + PFND3DKMT_OPENADAPTERFROMDEVICENAME _pfnOpen_adapter_device_name;
>
> > > + PFND3DKMT_OPENADAPTERFROMGDIDISPLAYNAME _pfnOpen_adapter_gdi_name;
>
> > > +
>
> > > + //object handles the CCD API
>
> > > + CCD _ccd;
>
> > > +};
>
> > > +
>
> > > +#endif
>
> > > \ No newline at end of file
>
As I said this patch is too big and should be split.
Frediano
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20160803/32e87c94/attachment-0001.html>
More information about the Spice-devel
mailing list