text:
/* $Id: VBoxDispIf.cpp $ */
/** @file
 * VBoxTray - Display Settings Interface abstraction for XPDM & WDDM
 */

/*
 * Copyright (C) 2006-2012 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#include "VBoxTray.h"
#define _WIN32_WINNT 0x0601
#include <iprt/log.h>
#include <iprt/err.h>
#include <iprt/assert.h>

#include <malloc.h>

#ifdef DEBUG_misha
#define WARN(_m) do { \
            Assert(0); \
            Log(_m); \
        } while (0)
#else
#define WARN(_m) do { \
            Log(_m); \
        } while (0)
#endif

#ifdef VBOX_WITH_WDDM
#include <iprt/asm.h>
#endif

#include "VBoxDisplay.h"

#ifndef NT_SUCCESS
# define NT_SUCCESS(_Status) ((_Status) >= 0)
#endif

typedef struct VBOXDISPIF_OP
{
    PCVBOXDISPIF pIf;
    VBOXDISPKMT_ADAPTER Adapter;
    VBOXDISPKMT_DEVICE Device;
    VBOXDISPKMT_CONTEXT Context;
} VBOXDISPIF_OP;

DWORD EnableAndResizeDispDev(DEVMODE *paDeviceModes, DISPLAY_DEVICE *paDisplayDevices, DWORD totalDispNum, UINT Id, DWORD aWidth, DWORD aHeight,
                                    DWORD aBitsPerPixel, LONG aPosX, LONG aPosY, BOOL fEnabled, BOOL fExtDispSup);

static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE * paDisplayDevices, DEVMODE *paDeviceMode, UINT devModes);

static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);

static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable);

static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp);

/* APIs specific to win7 and above WDDM architecture. Not available for Vista WDDM.
 * This is the reason they have not been put in the VBOXDISPIF struct in VBoxDispIf.h
 */
typedef struct _VBOXDISPLAYWDDMAPICONTEXT
{
    LONG (WINAPI * pfnSetDisplayConfig)(UINT numPathArrayElements,DISPLAYCONFIG_PATH_INFO *pathArray,UINT numModeInfoArrayElements,
                                    DISPLAYCONFIG_MODE_INFO *modeInfoArray, UINT Flags);
    LONG (WINAPI * pfnQueryDisplayConfig)(UINT Flags,UINT *pNumPathArrayElements, DISPLAYCONFIG_PATH_INFO *pPathInfoArray,
                                      UINT *pNumModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO *pModeInfoArray,
                                      DISPLAYCONFIG_TOPOLOGY_ID *pCurrentTopologyId);
    LONG (WINAPI * pfnGetDisplayConfigBufferSizes)(UINT Flags, UINT *pNumPathArrayElements, UINT *pNumModeInfoArrayElements);
} _VBOXDISPLAYWDDMAPICONTEXT;

static _VBOXDISPLAYWDDMAPICONTEXT gCtx = {0};

typedef struct VBOXDISPIF_WDDM_DISPCFG
{
    UINT32 cPathInfoArray;
    DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
    UINT32 cModeInfoArray;
    DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
} VBOXDISPIF_WDDM_DISPCFG;

static DWORD vboxDispIfWddmDcCreate(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT32 fFlags)
{
    UINT32 cPathInfoArray = 0;
    UINT32 cModeInfoArray = 0;
    DISPLAYCONFIG_PATH_INFO *pPathInfoArray;
    DISPLAYCONFIG_MODE_INFO *pModeInfoArray;
    DWORD winEr = gCtx.pfnGetDisplayConfigBufferSizes(fFlags, &cPathInfoArray, &cModeInfoArray);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray: (WDDM) Failed GetDisplayConfigBufferSizes\n"));
        return winEr;
    }

    pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(cPathInfoArray * sizeof(DISPLAYCONFIG_PATH_INFO));
    if (!pPathInfoArray)
    {
        WARN(("VBoxTray: (WDDM) malloc failed!\n"));
        return ERROR_OUTOFMEMORY;
    }
    pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
    if (!pModeInfoArray)
    {
        WARN(("VBoxTray: (WDDM) malloc failed!\n"));
        free(pPathInfoArray);
        return ERROR_OUTOFMEMORY;
    }

    winEr = gCtx.pfnQueryDisplayConfig(fFlags, &cPathInfoArray, pPathInfoArray, &cModeInfoArray, pModeInfoArray, NULL);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray: (WDDM) Failed QueryDisplayConfig\n"));
        free(pPathInfoArray);
        free(pModeInfoArray);
        return winEr;
    }

    pCfg->cPathInfoArray = cPathInfoArray;
    pCfg->pPathInfoArray = pPathInfoArray;
    pCfg->cModeInfoArray = cModeInfoArray;
    pCfg->pModeInfoArray = pModeInfoArray;
    return ERROR_SUCCESS;
}

static DWORD vboxDispIfWddmDcClone(VBOXDISPIF_WDDM_DISPCFG *pCfg, VBOXDISPIF_WDDM_DISPCFG *pCfgDst)
{
    memset(pCfgDst, 0, sizeof (*pCfgDst));

    if (pCfg->cPathInfoArray)
    {
        pCfgDst->pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));
        if (!pCfgDst->pPathInfoArray)
        {
            WARN(("VBoxTray: (WDDM) malloc failed!\n"));
            return ERROR_OUTOFMEMORY;
        }

        memcpy(pCfgDst->pPathInfoArray, pCfg->pPathInfoArray, pCfg->cPathInfoArray * sizeof (DISPLAYCONFIG_PATH_INFO));

        pCfgDst->cPathInfoArray = pCfg->cPathInfoArray;
    }

    if (pCfg->cModeInfoArray)
    {
        pCfgDst->pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
        if (!pCfgDst->pModeInfoArray)
        {
            WARN(("VBoxTray: (WDDM) malloc failed!\n"));
            if (pCfgDst->pPathInfoArray)
            {
                free(pCfgDst->pPathInfoArray);
                pCfgDst->pPathInfoArray = NULL;
            }
            return ERROR_OUTOFMEMORY;
        }

        memcpy(pCfgDst->pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));

        pCfgDst->cModeInfoArray = pCfg->cModeInfoArray;
    }

    return ERROR_SUCCESS;
}

static VOID vboxDispIfWddmDcTerm(VBOXDISPIF_WDDM_DISPCFG *pCfg)
{
    if (pCfg->pPathInfoArray)
        free(pCfg->pPathInfoArray);
    if (pCfg->pModeInfoArray)
        free(pCfg->pModeInfoArray);
    /* sanity */
    memset(pCfg, 0, sizeof (*pCfg));
}

static UINT32 g_cVBoxDispIfWddmDisplays = 0;
static DWORD vboxDispIfWddmDcQueryNumDisplays(UINT32 *pcDisplays)
{
    if (!g_cVBoxDispIfWddmDisplays)
    {
        VBOXDISPIF_WDDM_DISPCFG DispCfg;
        *pcDisplays = 0;
        DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
        if (winEr != ERROR_SUCCESS)
        {
            WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcCreate Failed winEr %d\n", winEr));
            return winEr;
        }

        int cDisplays = -1;

        for (UINT iter = 0; iter < DispCfg.cPathInfoArray; ++iter)
        {
            if (cDisplays < (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id))
                cDisplays = (int)(DispCfg.pPathInfoArray[iter].sourceInfo.id);
        }

        cDisplays++;

        g_cVBoxDispIfWddmDisplays = cDisplays;
        Assert(g_cVBoxDispIfWddmDisplays);

        vboxDispIfWddmDcTerm(&DispCfg);
    }

    *pcDisplays = g_cVBoxDispIfWddmDisplays;
    return ERROR_SUCCESS;
}

static int vboxDispIfWddmDcSearchPath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
{
    for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
    {
        if ((srcId == ~0UL || pCfg->pPathInfoArray[iter].sourceInfo.id == srcId)
                && (trgId == ~0UL || pCfg->pPathInfoArray[iter].targetInfo.id == trgId))
        {
            return (int)iter;
        }
    }
    return -1;
}

static int vboxDispIfWddmDcSearchActivePath(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT srcId, UINT trgId)
{
    int idx = vboxDispIfWddmDcSearchPath(pCfg, srcId, trgId);
    if (idx < 0)
        return idx;

    if (!(pCfg->pPathInfoArray[idx].flags & DISPLAYCONFIG_PATH_ACTIVE))
        return -1;

    return idx;
}

static VOID vboxDispIfWddmDcSettingsInvalidateModeIndex(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx)
{
    pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
    pCfg->pPathInfoArray[idx].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
}

static VOID vboxDispIfWddmDcSettingsInvalidateModeIndeces(VBOXDISPIF_WDDM_DISPCFG *pCfg)
{
    for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
    {
        vboxDispIfWddmDcSettingsInvalidateModeIndex(pCfg, (int)iter);
    }

    if (pCfg->pModeInfoArray)
    {
        free(pCfg->pModeInfoArray);
        pCfg->pModeInfoArray = NULL;
    }
    pCfg->cModeInfoArray = 0;
}

static DWORD vboxDispIfWddmDcSettingsModeAdd(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT *pIdx)
{
    UINT32 cModeInfoArray = pCfg->cModeInfoArray + 1;
    DISPLAYCONFIG_MODE_INFO *pModeInfoArray = (DISPLAYCONFIG_MODE_INFO *)malloc(cModeInfoArray * sizeof (DISPLAYCONFIG_MODE_INFO));
    if (!pModeInfoArray)
    {
        WARN(("VBoxTray: (WDDM) malloc failed!\n"));
        return ERROR_OUTOFMEMORY;
    }

    memcpy (pModeInfoArray, pCfg->pModeInfoArray, pCfg->cModeInfoArray * sizeof(DISPLAYCONFIG_MODE_INFO));
    memset(&pModeInfoArray[cModeInfoArray-1], 0, sizeof (pModeInfoArray[0]));
    free(pCfg->pModeInfoArray);
    *pIdx = cModeInfoArray-1;
    pCfg->pModeInfoArray = pModeInfoArray;
    pCfg->cModeInfoArray = cModeInfoArray;
    return ERROR_SUCCESS;
}

static DWORD vboxDispIfWddmDcSettingsUpdate(VBOXDISPIF_WDDM_DISPCFG *pCfg, int idx, DEVMODE *pDeviceMode, BOOL fInvalidateSrcMode, BOOL fEnable)
{
    UINT Id = pCfg->pPathInfoArray[idx].sourceInfo.id;

    if (fInvalidateSrcMode)
        pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
    else if (pDeviceMode)
    {
        UINT iSrcMode = pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx;
        if (iSrcMode == DISPLAYCONFIG_PATH_MODE_IDX_INVALID)
        {

            WARN(("VBoxTray: (WDDM) no source mode index specified"));
            DWORD winEr = vboxDispIfWddmDcSettingsModeAdd(pCfg, &iSrcMode);
            if (winEr != ERROR_SUCCESS)
            {
                WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcSettingsModeAdd Failed winEr %d\n", winEr));
                return winEr;
            }
            pCfg->pPathInfoArray[idx].sourceInfo.modeInfoIdx = iSrcMode;
        }

        for (int i = 0; i < (int)pCfg->cPathInfoArray; ++i)
        {
            if (i == idx)
                continue;

            if (pCfg->pPathInfoArray[i].sourceInfo.modeInfoIdx == iSrcMode)
            {
                /* this is something we're not expecting/supporting */
                WARN(("VBoxTray: (WDDM) multiple paths have the same mode index"));
                return ERROR_NOT_SUPPORTED;
            }
        }

        if (pDeviceMode->dmFields & DM_PELSWIDTH)
            pCfg->pModeInfoArray[iSrcMode].sourceMode.width = pDeviceMode->dmPelsWidth;
        if (pDeviceMode->dmFields & DM_PELSHEIGHT)
            pCfg->pModeInfoArray[iSrcMode].sourceMode.height = pDeviceMode->dmPelsHeight;
        if (pDeviceMode->dmFields & DM_POSITION)
        {
            LogFlowFunc(("DM_POSITION %d,%d -> %d,%d\n",
                         pCfg->pModeInfoArray[iSrcMode].sourceMode.position.x,
                         pCfg->pModeInfoArray[iSrcMode].sourceMode.position.y,
                         pDeviceMode->dmPosition.x, pDeviceMode->dmPosition.y));
            pCfg->pModeInfoArray[iSrcMode].sourceMode.position.x = pDeviceMode->dmPosition.x;
            pCfg->pModeInfoArray[iSrcMode].sourceMode.position.y = pDeviceMode->dmPosition.y;
        }
        if (pDeviceMode->dmFields & DM_BITSPERPEL)
        {
            switch (pDeviceMode->dmBitsPerPel)
            {
                case 32:
                    pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
                    break;
                case 24:
                    pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_24BPP;
                    break;
                case 16:
                    pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_16BPP;
                    break;
                case 8:
                    pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_8BPP;
                    break;
                default:
                    LogRel(("VBoxTray: (WDDM) invalid bpp %d, using 32\n", pDeviceMode->dmBitsPerPel));
                    pCfg->pModeInfoArray[iSrcMode].sourceMode.pixelFormat = DISPLAYCONFIG_PIXELFORMAT_32BPP;
                    break;
            }
        }
    }

    pCfg->pPathInfoArray[idx].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;

    if (fEnable)
        pCfg->pPathInfoArray[idx].flags |= DISPLAYCONFIG_PATH_ACTIVE;
    else
        pCfg->pPathInfoArray[idx].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;

    return ERROR_SUCCESS;
}

static DWORD vboxDispIfWddmDcSet(VBOXDISPIF_WDDM_DISPCFG *pCfg, UINT fFlags)
{
    DWORD winEr = gCtx.pfnSetDisplayConfig(pCfg->cPathInfoArray, pCfg->pPathInfoArray, pCfg->cModeInfoArray, pCfg->pModeInfoArray, fFlags);
    if (winEr != ERROR_SUCCESS)
        Log(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed for Flags 0x%x\n", fFlags));
    return winEr;
}

static BOOL vboxDispIfWddmDcSettingsAdjustSupportedPaths(VBOXDISPIF_WDDM_DISPCFG *pCfg)
{
    BOOL fAdjusted = FALSE;
    for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
    {
        if (pCfg->pPathInfoArray[iter].sourceInfo.id == pCfg->pPathInfoArray[iter].targetInfo.id)
            continue;

        if (!(pCfg->pPathInfoArray[iter].flags & DISPLAYCONFIG_PATH_ACTIVE))
            continue;

        pCfg->pPathInfoArray[iter].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
        fAdjusted = TRUE;
    }

    return fAdjusted;
}

static void vboxDispIfWddmDcSettingsAttachDisbledToPrimary(VBOXDISPIF_WDDM_DISPCFG *pCfg)
{
    for (UINT iter = 0; iter < pCfg->cPathInfoArray; ++iter)
    {
        if ((pCfg->pPathInfoArray[iter].flags & DISPLAYCONFIG_PATH_ACTIVE))
            continue;

        pCfg->pPathInfoArray[iter].sourceInfo.id = 0;
        pCfg->pPathInfoArray[iter].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
        pCfg->pPathInfoArray[iter].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
    }
}

static DWORD vboxDispIfWddmDcSettingsIncludeAllTargets(VBOXDISPIF_WDDM_DISPCFG *pCfg)
{
    UINT32 cDisplays = 0;
    VBOXDISPIF_WDDM_DISPCFG AllCfg;
    BOOL fAllCfgInited = FALSE;

    DWORD winEr = vboxDispIfWddmDcQueryNumDisplays(&cDisplays);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcQueryNumDisplays Failed winEr %d\n", winEr));
        return winEr;
    }

    DISPLAYCONFIG_PATH_INFO *pPathInfoArray = (DISPLAYCONFIG_PATH_INFO *)malloc(cDisplays * sizeof(DISPLAYCONFIG_PATH_INFO));
    if (!pPathInfoArray)
    {
        WARN(("malloc failed\n"));
        return ERROR_OUTOFMEMORY;
    }

    for (UINT i = 0; i < cDisplays; ++i)
    {
        int idx = vboxDispIfWddmDcSearchPath(pCfg, i, i);
        if (idx < 0)
        {
            idx = vboxDispIfWddmDcSearchPath(pCfg, -1, i);
            if (idx >= 0)
            {
                WARN(("VBoxTray:(WDDM) different source and target paare enabled, this is something we would not expect\n"));
            }
        }

        if (idx >= 0)
            pPathInfoArray[i] = pCfg->pPathInfoArray[idx];
        else
        {
            if (!fAllCfgInited)
            {
                winEr = vboxDispIfWddmDcCreate(&AllCfg, QDC_ALL_PATHS);
                if (winEr != ERROR_SUCCESS)
                {
                    WARN(("VBoxTray:(WDDM) vboxDispIfWddmDcCreate Failed winEr %d\n", winEr));
                    free(pPathInfoArray);
                    return winEr;
                }
                fAllCfgInited = TRUE;
            }

            idx = vboxDispIfWddmDcSearchPath(&AllCfg, i, i);
            if (idx < 0)
            {
                WARN(("VBoxTray:(WDDM) %d %d path not supported\n", i, i));
                idx = vboxDispIfWddmDcSearchPath(pCfg, -1, i);
                if (idx < 0)
                {
                    WARN(("VBoxTray:(WDDM) %d %d path not supported\n", -1, i));
                }
            }

            if (idx >= 0)
            {
                pPathInfoArray[i] = AllCfg.pPathInfoArray[idx];

                if (pPathInfoArray[i].flags & DISPLAYCONFIG_PATH_ACTIVE)
                {
                    WARN(("VBoxTray:(WDDM) disabled path %d %d is marked active\n",
                            pPathInfoArray[i].sourceInfo.id, pPathInfoArray[i].targetInfo.id));
                    pPathInfoArray[i].flags &= ~DISPLAYCONFIG_PATH_ACTIVE;
                }

                Assert(pPathInfoArray[i].sourceInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID);
                Assert(pPathInfoArray[i].sourceInfo.statusFlags == 0);

                Assert(pPathInfoArray[i].targetInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID);
                Assert(pPathInfoArray[i].targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15);
                Assert(pPathInfoArray[i].targetInfo.rotation == DISPLAYCONFIG_ROTATION_IDENTITY);
                Assert(pPathInfoArray[i].targetInfo.scaling == DISPLAYCONFIG_SCALING_PREFERRED);
                Assert(pPathInfoArray[i].targetInfo.refreshRate.Numerator == 0);
                Assert(pPathInfoArray[i].targetInfo.refreshRate.Denominator == 0);
                Assert(pPathInfoArray[i].targetInfo.scanLineOrdering == DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED);
                Assert(pPathInfoArray[i].targetInfo.targetAvailable == TRUE);
                Assert(pPathInfoArray[i].targetInfo.statusFlags == DISPLAYCONFIG_TARGET_FORCIBLE);

                Assert(pPathInfoArray[i].flags == 0);
            }
            else
            {
                pPathInfoArray[i].sourceInfo.adapterId = pCfg->pPathInfoArray[0].sourceInfo.adapterId;
                pPathInfoArray[i].sourceInfo.id = i;
                pPathInfoArray[i].sourceInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
                pPathInfoArray[i].sourceInfo.statusFlags = 0;

                pPathInfoArray[i].targetInfo.adapterId = pPathInfoArray[i].sourceInfo.adapterId;
                pPathInfoArray[i].targetInfo.id = i;
                pPathInfoArray[i].targetInfo.modeInfoIdx = DISPLAYCONFIG_PATH_MODE_IDX_INVALID;
                pPathInfoArray[i].targetInfo.outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15;
                pPathInfoArray[i].targetInfo.rotation = DISPLAYCONFIG_ROTATION_IDENTITY;
                pPathInfoArray[i].targetInfo.scaling = DISPLAYCONFIG_SCALING_PREFERRED;
                pPathInfoArray[i].targetInfo.refreshRate.Numerator = 0;
                pPathInfoArray[i].targetInfo.refreshRate.Denominator = 0;
                pPathInfoArray[i].targetInfo.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
                pPathInfoArray[i].targetInfo.targetAvailable = TRUE;
                pPathInfoArray[i].targetInfo.statusFlags = DISPLAYCONFIG_TARGET_FORCIBLE;

                pPathInfoArray[i].flags = 0;
            }
        }
    }

    free(pCfg->pPathInfoArray);
    pCfg->pPathInfoArray = pPathInfoArray;
    pCfg->cPathInfoArray = cDisplays;
    if (fAllCfgInited)
        vboxDispIfWddmDcTerm(&AllCfg);

    return ERROR_SUCCESS;
}

static DWORD vboxDispIfOpBegin(PCVBOXDISPIF pIf, VBOXDISPIF_OP *pOp)
{
    pOp->pIf = pIf;

    HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pOp->Adapter);
    if (SUCCEEDED(hr))
    {
        hr = vboxDispKmtCreateDevice(&pOp->Adapter, &pOp->Device);
        if (SUCCEEDED(hr))
        {
            hr = vboxDispKmtCreateContext(&pOp->Device, &pOp->Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_RESIZE,
                    0, 0, NULL, 0ULL);
            if (SUCCEEDED(hr))
                return ERROR_SUCCESS;
            else
                WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));

            vboxDispKmtDestroyDevice(&pOp->Device);
        }
        else
            WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));

        vboxDispKmtCloseAdapter(&pOp->Adapter);
    }

    return hr;
}

static VOID vboxDispIfOpEnd(VBOXDISPIF_OP *pOp)
{
    vboxDispKmtDestroyContext(&pOp->Context);
    vboxDispKmtDestroyDevice(&pOp->Device);
    vboxDispKmtCloseAdapter(&pOp->Adapter);
}

/* display driver interface abstraction for XPDM & WDDM
 * with WDDM we can not use ExtEscape to communicate with our driver
 * because we do not have XPDM display driver any more, i.e. escape requests are handled by cdd
 * that knows nothing about us */
DWORD VBoxDispIfInit(PVBOXDISPIF pIf)
{
    pIf->enmMode = VBOXDISPIF_MODE_XPDM;
    return NO_ERROR;
}

#ifdef VBOX_WITH_WDDM
static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf);
static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf);
#endif

DWORD VBoxDispIfTerm(PVBOXDISPIF pIf)
{
#ifdef VBOX_WITH_WDDM
    if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
    {
        vboxDispIfWddmTerm(pIf);

        vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
    }
#endif

    pIf->enmMode = VBOXDISPIF_MODE_UNKNOWN;
    return NO_ERROR;
}

static DWORD vboxDispIfEscapeXPDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, int iDirection)
{
    HDC  hdc = GetDC(HWND_DESKTOP);
    VOID *pvData = cbData ? VBOXDISPIFESCAPE_DATA(pEscape, VOID) : NULL;
    int iRet = ExtEscape(hdc, pEscape->escapeCode,
            iDirection >= 0 ? cbData : 0,
            iDirection >= 0 ? (LPSTR)pvData : NULL,
            iDirection <= 0 ? cbData : 0,
            iDirection <= 0 ? (LPSTR)pvData : NULL);
    ReleaseDC(HWND_DESKTOP, hdc);
    if (iRet > 0)
        return VINF_SUCCESS;
    else if (iRet == 0)
        return ERROR_NOT_SUPPORTED;
    /* else */
    return ERROR_GEN_FAILURE;
}

#ifdef VBOX_WITH_WDDM
static DWORD vboxDispIfSwitchToWDDM(PVBOXDISPIF pIf)
{
    DWORD err = NO_ERROR;
    OSVERSIONINFO OSinfo;
    OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
    GetVersionEx (&OSinfo);
    bool bSupported = true;

    if (OSinfo.dwMajorVersion >= 6)
    {
        Log((__FUNCTION__": this is vista and up\n"));
        HMODULE hUser = GetModuleHandle("user32.dll");
        if (hUser)
        {
            *(uintptr_t *)&pIf->modeData.wddm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
            Log((__FUNCTION__": VBoxDisplayInit: pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.wddm.pfnChangeDisplaySettingsEx));
            bSupported &= !!(pIf->modeData.wddm.pfnChangeDisplaySettingsEx);

            *(uintptr_t *)&pIf->modeData.wddm.pfnEnumDisplayDevices = (uintptr_t)GetProcAddress(hUser, "EnumDisplayDevicesA");
            Log((__FUNCTION__": VBoxDisplayInit: pfnEnumDisplayDevices = %p\n", pIf->modeData.wddm.pfnEnumDisplayDevices));
            bSupported &= !!(pIf->modeData.wddm.pfnEnumDisplayDevices);
            /* for win 7 and above */
             if (OSinfo.dwMinorVersion >= 1)
            {
                *(uintptr_t *)&gCtx.pfnSetDisplayConfig = (uintptr_t)GetProcAddress(hUser, "SetDisplayConfig");
                Log((__FUNCTION__": VBoxDisplayInit: pfnSetDisplayConfig = %p\n", gCtx.pfnSetDisplayConfig));
                bSupported &= !!(gCtx.pfnSetDisplayConfig);

                *(uintptr_t *)&gCtx.pfnQueryDisplayConfig = (uintptr_t)GetProcAddress(hUser, "QueryDisplayConfig");
                Log((__FUNCTION__": VBoxDisplayInit: pfnQueryDisplayConfig = %p\n", gCtx.pfnQueryDisplayConfig));
                bSupported &= !!(gCtx.pfnQueryDisplayConfig);

                *(uintptr_t *)&gCtx.pfnGetDisplayConfigBufferSizes = (uintptr_t)GetProcAddress(hUser, "GetDisplayConfigBufferSizes");
                Log((__FUNCTION__": VBoxDisplayInit: pfnGetDisplayConfigBufferSizes = %p\n", gCtx.pfnGetDisplayConfigBufferSizes));
                bSupported &= !!(gCtx.pfnGetDisplayConfigBufferSizes);
            }

            /* this is vista and up */
            HRESULT hr = vboxDispKmtCallbacksInit(&pIf->modeData.wddm.KmtCallbacks);
            if (FAILED(hr))
            {
                WARN(("VBoxTray: vboxDispKmtCallbacksInit failed hr 0x%x\n", hr));
                err = hr;
            }
        }
        else
        {
            WARN((__FUNCTION__": GetModuleHandle(USER32) failed, err(%d)\n", GetLastError()));
            err = ERROR_NOT_SUPPORTED;
        }
    }
    else
    {
        WARN((__FUNCTION__": can not switch to VBOXDISPIF_MODE_WDDM, because os is not Vista or upper\n"));
        err = ERROR_NOT_SUPPORTED;
    }

    if (err == ERROR_SUCCESS)
    {
        err = vboxDispIfWddmInit(pIf);
    }

    return err;
}

static DWORD vboxDispIfSwitchToWDDM_W7(PVBOXDISPIF pIf)
{
    return vboxDispIfSwitchToWDDM(pIf);
}

static DWORD vboxDispIfWDDMAdpHdcCreate(int iDisplay, HDC *phDc, DISPLAY_DEVICE *pDev)
{
    DWORD winEr = ERROR_INVALID_STATE;
    memset(pDev, 0, sizeof (*pDev));
    pDev->cb = sizeof (*pDev);

    for (int i = 0; ; ++i)
    {
        if (EnumDisplayDevices(NULL, /* LPCTSTR lpDevice */ i, /* DWORD iDevNum */
                pDev, 0 /* DWORD dwFlags*/))
        {
            if (i == iDisplay || (iDisplay < 0 && pDev->StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
            {
                HDC hDc = CreateDC(NULL, pDev->DeviceName, NULL, NULL);
                if (hDc)
                {
                    *phDc = hDc;
                    return NO_ERROR;
                }
                else
                {
                    winEr = GetLastError();
                    WARN(("CreateDC failed %d", winEr));
                    break;
                }
            }
            Log(("display data no match display(%d): i(%d), flags(%d)", iDisplay, i, pDev->StateFlags));
        }
        else
        {
            winEr = GetLastError();
            WARN(("EnumDisplayDevices failed %d", winEr));
            break;
        }
    }

    WARN(("vboxDispIfWDDMAdpHdcCreate failure branch %d", winEr));
    return winEr;
}

static DWORD vboxDispIfEscapeWDDM(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData, BOOL fHwAccess)
{
    DWORD winEr = ERROR_SUCCESS;
    VBOXDISPKMT_ADAPTER Adapter;
    HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &Adapter);
    if (!SUCCEEDED(hr))
    {
        WARN(("VBoxTray: vboxDispKmtOpenAdapter failed hr 0x%x\n", hr));
        return hr;
    }

    D3DKMT_ESCAPE EscapeData = {0};
    EscapeData.hAdapter = Adapter.hAdapter;
    //EscapeData.hDevice = NULL;
    EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
    if (fHwAccess)
        EscapeData.Flags.HardwareAccess = 1;
    EscapeData.pPrivateDriverData = pEscape;
    EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);
    //EscapeData.hContext = NULL;

    NTSTATUS Status = pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
    if (NT_SUCCESS(Status))
        winEr = ERROR_SUCCESS;
    else
    {
        WARN(("VBoxTray: pfnD3DKMTEscape failed Status 0x%x\n", Status));
        winEr = ERROR_GEN_FAILURE;
    }

    vboxDispKmtCloseAdapter(&Adapter);

    return winEr;
}
#endif

DWORD VBoxDispIfEscape(PCVBOXDISPIF pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
{
    switch (pIf->enmMode)
    {
        case VBOXDISPIF_MODE_XPDM_NT4:
        case VBOXDISPIF_MODE_XPDM:
            return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 1);
#ifdef VBOX_WITH_WDDM
        case VBOXDISPIF_MODE_WDDM:
        case VBOXDISPIF_MODE_WDDM_W7:
            return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
#endif
        default:
            Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
            return ERROR_INVALID_PARAMETER;
    }
}

DWORD VBoxDispIfEscapeInOut(PCVBOXDISPIF const pIf, PVBOXDISPIFESCAPE pEscape, int cbData)
{
    switch (pIf->enmMode)
    {
        case VBOXDISPIF_MODE_XPDM_NT4:
        case VBOXDISPIF_MODE_XPDM:
            return vboxDispIfEscapeXPDM(pIf, pEscape, cbData, 0);
#ifdef VBOX_WITH_WDDM
        case VBOXDISPIF_MODE_WDDM:
        case VBOXDISPIF_MODE_WDDM_W7:
            return vboxDispIfEscapeWDDM(pIf, pEscape, cbData, TRUE /* BOOL fHwAccess */);
#endif
        default:
            Log((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
            return ERROR_INVALID_PARAMETER;
    }
}

#ifdef VBOX_WITH_WDDM

#define VBOXRR_TIMER_ID 1234

typedef struct VBOXRR
{
    HANDLE hThread;
    DWORD idThread;
    HANDLE hEvent;
    HWND hWnd;
    CRITICAL_SECTION CritSect;
    UINT_PTR idTimer;
    PCVBOXDISPIF pIf;
    UINT iChangedMode;
    BOOL fEnable;
    BOOL fExtDispSup;
    DISPLAY_DEVICE *paDisplayDevices;
    DEVMODE *paDeviceModes;
    UINT cDevModes;
} VBOXRR, *PVBOXRR;

static VBOXRR g_VBoxRr = {0};

#define VBOX_E_INSUFFICIENT_BUFFER HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
#define VBOX_E_NOT_SUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)

static void vboxRrRetryStopLocked()
{
    PVBOXRR pMon = &g_VBoxRr;
    if (pMon->pIf)
    {
        if (pMon->paDisplayDevices)
        {
            free(pMon->paDisplayDevices);
            pMon->paDisplayDevices = NULL;
        }

        if (pMon->paDeviceModes)
        {
            free(pMon->paDeviceModes);
            pMon->paDeviceModes = NULL;
        }

        if (pMon->idTimer)
        {
            KillTimer(pMon->hWnd, pMon->idTimer);
            pMon->idTimer = 0;
        }

        pMon->cDevModes = 0;
        pMon->pIf = NULL;
    }
}

static void VBoxRrRetryStop()
{
    PVBOXRR pMon = &g_VBoxRr;
    EnterCriticalSection(&pMon->CritSect);
    vboxRrRetryStopLocked();
    LeaveCriticalSection(&pMon->CritSect);
}

//static DWORD vboxDispIfWddmValidateFixResize(PCVBOXDISPIF const pIf, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes);

static void vboxRrRetryReschedule()
{
}

static void VBoxRrRetrySchedule(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
{
    PVBOXRR pMon = &g_VBoxRr;
    EnterCriticalSection(&pMon->CritSect);
    vboxRrRetryStopLocked();

    pMon->pIf = pIf;
    pMon->iChangedMode = iChangedMode;
    pMon->fEnable = fEnable;
    pMon->fExtDispSup = fExtDispSup;

    if (cDevModes)
    {
        pMon->paDisplayDevices = (DISPLAY_DEVICE*)malloc(sizeof (*paDisplayDevices) * cDevModes);
        Assert(pMon->paDisplayDevices);
        if (!pMon->paDisplayDevices)
        {
            Log(("malloc failed!"));
            vboxRrRetryStopLocked();
            LeaveCriticalSection(&pMon->CritSect);
            return;
        }
        memcpy(pMon->paDisplayDevices, paDisplayDevices, sizeof (*paDisplayDevices) * cDevModes);

        pMon->paDeviceModes = (DEVMODE*)malloc(sizeof (*paDeviceModes) * cDevModes);
        Assert(pMon->paDeviceModes);
        if (!pMon->paDeviceModes)
        {
            Log(("malloc failed!"));
            vboxRrRetryStopLocked();
            LeaveCriticalSection(&pMon->CritSect);
            return;
        }
        memcpy(pMon->paDeviceModes, paDeviceModes, sizeof (*paDeviceModes) * cDevModes);
    }
    pMon->cDevModes = cDevModes;

    pMon->idTimer = SetTimer(pMon->hWnd, VBOXRR_TIMER_ID, 1000, (TIMERPROC)NULL);
    Assert(pMon->idTimer);
    if (!pMon->idTimer)
    {
        WARN(("VBoxTray: SetTimer failed!, err %d\n", GetLastError()));
        vboxRrRetryStopLocked();
    }

    LeaveCriticalSection(&pMon->CritSect);
}

static void vboxRrRetryPerform()
{
    PVBOXRR pMon = &g_VBoxRr;
    EnterCriticalSection(&pMon->CritSect);
    if (pMon->pIf)
    {
        DWORD dwErr = vboxDispIfResizePerform(pMon->pIf, pMon->iChangedMode, pMon->fEnable, pMon->fExtDispSup, pMon->paDisplayDevices, pMon->paDeviceModes, pMon->cDevModes);
        if (ERROR_RETRY != dwErr)
            VBoxRrRetryStop();
        else
            vboxRrRetryReschedule();
    }
    LeaveCriticalSection(&pMon->CritSect);
}

static LRESULT CALLBACK vboxRrWndProc(HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
)
{
    switch(uMsg)
    {
        case WM_DISPLAYCHANGE:
        {
            Log(("VBoxTray: WM_DISPLAYCHANGE\n"));
            VBoxRrRetryStop();
            return 0;
        }
        case WM_TIMER:
        {
            if (wParam == VBOXRR_TIMER_ID)
            {
                Log(("VBoxTray: VBOXRR_TIMER_ID\n"));
                vboxRrRetryPerform();
                return 0;
            }
            break;
        }
        case WM_CLOSE:
            Log((__FUNCTION__": got WM_CLOSE for hwnd(0x%x)", hwnd));
            return 0;
        case WM_DESTROY:
            Log((__FUNCTION__": got WM_DESTROY for hwnd(0x%x)", hwnd));
            return 0;
        case WM_NCHITTEST:
            Log((__FUNCTION__": got WM_NCHITTEST for hwnd(0x%x)\n", hwnd));
            return HTNOWHERE;
        default:
            break;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

#define VBOXRRWND_NAME "VBoxRrWnd"

static HRESULT vboxRrWndCreate(HWND *phWnd)
{
    HRESULT hr = S_OK;
    HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
    /* Register the Window Class. */
    WNDCLASS wc;
    if (!GetClassInfo(hInstance, VBOXRRWND_NAME, &wc))
    {
        wc.style = 0;//CS_OWNDC;
        wc.lpfnWndProc = vboxRrWndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = NULL;
        wc.hCursor = NULL;
        wc.hbrBackground = NULL;
        wc.lpszMenuName = NULL;
        wc.lpszClassName = VBOXRRWND_NAME;
        if (!RegisterClass(&wc))
        {
            DWORD winErr = GetLastError();
            WARN((__FUNCTION__": RegisterClass failed, winErr(%d)\n", winErr));
            hr = E_FAIL;
        }
    }

    if (hr == S_OK)
    {
        HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
                                        VBOXRRWND_NAME, VBOXRRWND_NAME,
                                        WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
                                        -100, -100,
                                        10, 10,
                                        NULL, //GetDesktopWindow() /* hWndParent */,
                                        NULL /* hMenu */,
                                        hInstance,
                                        NULL /* lpParam */);
        Assert(hWnd);
        if (hWnd)
        {
            *phWnd = hWnd;
        }
        else
        {
            DWORD winErr = GetLastError();
            WARN((__FUNCTION__": CreateWindowEx failed, winErr(%d)\n", winErr));
            hr = E_FAIL;
        }
    }

    return hr;
}

static HRESULT vboxRrWndDestroy(HWND hWnd)
{
    BOOL bResult = DestroyWindow(hWnd);
    if (bResult)
        return S_OK;

    DWORD winErr = GetLastError();
    WARN((__FUNCTION__": DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd));

    return HRESULT_FROM_WIN32(winErr);
}

static HRESULT vboxRrWndInit()
{
    PVBOXRR pMon = &g_VBoxRr;
    return vboxRrWndCreate(&pMon->hWnd);
}

HRESULT vboxRrWndTerm()
{
    PVBOXRR pMon = &g_VBoxRr;
    HRESULT tmpHr = vboxRrWndDestroy(pMon->hWnd);
    Assert(tmpHr == S_OK);

    HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
    UnregisterClass(VBOXRRWND_NAME, hInstance);

    return S_OK;
}

#define WM_VBOXRR_INIT_QUIT (WM_APP+2)

HRESULT vboxRrRun()
{
    PVBOXRR pMon = &g_VBoxRr;
    MSG Msg;

    HRESULT hr = S_FALSE;

    PeekMessage(&Msg,
            NULL /* HWND hWnd */,
            WM_USER /* UINT wMsgFilterMin */,
            WM_USER /* UINT wMsgFilterMax */,
            PM_NOREMOVE);

    do
    {
        BOOL bResult = GetMessage(&Msg,
            0 /*HWND hWnd*/,
            0 /*UINT wMsgFilterMin*/,
            0 /*UINT wMsgFilterMax*/
            );

        if(!bResult) /* WM_QUIT was posted */
        {
            hr = S_FALSE;
            Log(("VBoxTray: GetMessage returned FALSE\n"));
            VBoxRrRetryStop();
            break;
        }

        if(bResult == -1) /* error occurred */
        {
            DWORD winEr = GetLastError();
            hr = HRESULT_FROM_WIN32(winEr);
            /* just ensure we never return success in this case */
            Assert(hr != S_OK);
            Assert(hr != S_FALSE);
            if (hr == S_OK || hr == S_FALSE)
                hr = E_FAIL;
            WARN(("VBoxTray: GetMessage returned -1, err %d\n", winEr));
            VBoxRrRetryStop();
            break;
        }

        switch (Msg.message)
        {
            case WM_VBOXRR_INIT_QUIT:
            case WM_CLOSE:
            {
                Log(("VBoxTray: closing Rr %d\n", Msg.message));
                VBoxRrRetryStop();
                PostQuitMessage(0);
                break;
            }
            default:
                TranslateMessage(&Msg);
                DispatchMessage(&Msg);
                break;
        }
    } while (1);
    return 0;
}

static DWORD WINAPI vboxRrRunnerThread(void *pvUser)
{
    PVBOXRR pMon = &g_VBoxRr;

    BOOL bRc = SetEvent(pMon->hEvent);
    if (!bRc)
    {
        DWORD winErr = GetLastError();
        WARN((__FUNCTION__": SetEvent failed, winErr = (%d)", winErr));
        HRESULT tmpHr = HRESULT_FROM_WIN32(winErr);
        Assert(tmpHr != S_OK);
    }

    HRESULT hr = vboxRrWndInit();
    Assert(hr == S_OK);
    if (hr == S_OK)
    {
        hr = vboxRrRun();
        Assert(hr == S_OK);

        vboxRrWndTerm();
    }

    return 0;
}

HRESULT VBoxRrInit()
{
    HRESULT hr = E_FAIL;
    PVBOXRR pMon = &g_VBoxRr;
    memset(pMon, 0, sizeof (*pMon));

    InitializeCriticalSection(&pMon->CritSect);

    pMon->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes*/
            TRUE, /* BOOL bManualReset*/
            FALSE, /* BOOL bInitialState */
            NULL /* LPCTSTR lpName */
          );
    if (pMon->hEvent)
    {
        pMon->hThread = CreateThread(NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
                                              0 /* SIZE_T dwStackSize */,
                                              vboxRrRunnerThread,
                                              pMon,
                                              0 /* DWORD dwCreationFlags */,
                                              &pMon->idThread);
        if (pMon->hThread)
        {
            DWORD dwResult = WaitForSingleObject(pMon->hEvent, INFINITE);
            if (dwResult == WAIT_OBJECT_0)
                return S_OK;
            else
            {
                Log(("WaitForSingleObject failed!"));
                hr = E_FAIL;
            }
        }
        else
        {
            DWORD winErr = GetLastError();
            WARN((__FUNCTION__": CreateThread failed, winErr = (%d)", winErr));
            hr = HRESULT_FROM_WIN32(winErr);
            Assert(hr != S_OK);
        }
        CloseHandle(pMon->hEvent);
    }
    else
    {
        DWORD winErr = GetLastError();
        WARN((__FUNCTION__": CreateEvent failed, winErr = (%d)", winErr));
        hr = HRESULT_FROM_WIN32(winErr);
        Assert(hr != S_OK);
    }

    DeleteCriticalSection(&pMon->CritSect);

    return hr;
}

VOID VBoxRrTerm()
{
    HRESULT hr;
    PVBOXRR pMon = &g_VBoxRr;
    if (!pMon->hThread)
        return;

    BOOL bResult = PostThreadMessage(pMon->idThread, WM_VBOXRR_INIT_QUIT, 0, 0);
    DWORD winErr;
    if (bResult
            || (winErr = GetLastError()) == ERROR_INVALID_THREAD_ID) /* <- could be that the thread is terminated */
    {
        DWORD dwErr = WaitForSingleObject(pMon->hThread, INFINITE);
        if (dwErr == WAIT_OBJECT_0)
        {
            hr = S_OK;
        }
        else
        {
            winErr = GetLastError();
            hr = HRESULT_FROM_WIN32(winErr);
        }
    }
    else
    {
        hr = HRESULT_FROM_WIN32(winErr);
    }

    DeleteCriticalSection(&pMon->CritSect);

    CloseHandle(pMon->hThread);
    pMon->hThread = 0;
    CloseHandle(pMon->hEvent);
    pMon->hThread = 0;
}

static DWORD vboxDispIfWddmInit(PCVBOXDISPIF pIf)
{
    HRESULT hr = VBoxRrInit();
    if (SUCCEEDED(hr))
    {
        return ERROR_SUCCESS;
    }
    WARN(("VBoxTray: VBoxRrInit failed hr 0x%x\n", hr));
    return hr;
}

static void vboxDispIfWddmTerm(PCVBOXDISPIF pIf)
{
    VBoxRrTerm();
}

static DWORD vboxDispIfQueryDisplayConnection(VBOXDISPIF_OP *pOp, UINT32 iDisplay, BOOL *pfConnected)
{
    if (pOp->pIf->enmMode == VBOXDISPIF_MODE_WDDM)
    {
        /* @todo: do we need ti impl it? */
        *pfConnected = TRUE;
        return ERROR_SUCCESS;
    }

    *pfConnected = FALSE;

    VBOXDISPIF_WDDM_DISPCFG DispCfg;
    DWORD winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ALL_PATHS);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
        return winEr;
    }

    int idx = vboxDispIfWddmDcSearchPath(&DispCfg, iDisplay, iDisplay);
    *pfConnected = (idx >= 0);

    vboxDispIfWddmDcTerm(&DispCfg);

    return ERROR_SUCCESS;
}

static DWORD vboxDispIfWaitDisplayDataInited(VBOXDISPIF_OP *pOp)
{
    DWORD winEr = ERROR_SUCCESS;
    do
    {
        Sleep(100);

        D3DKMT_POLLDISPLAYCHILDREN PollData = {0};
        PollData.hAdapter = pOp->Adapter.hAdapter;
        PollData.NonDestructiveOnly = 1;
        NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTPollDisplayChildren(&PollData);
        if (Status != 0)
        {
            Log(("VBoxTray: (WDDM) pfnD3DKMTPollDisplayChildren failed, Status (0x%x)\n", Status));
            continue;
        }

        BOOL fFound = FALSE;
#if 0
        for (UINT i = 0; i < VBOXWDDM_SCREENMASK_SIZE; ++i)
        {
            if (pu8DisplayMask && !ASMBitTest(pu8DisplayMask, i))
                continue;

            BOOL fConnected = FALSE;
            winEr = vboxDispIfQueryDisplayConnection(pOp, i, &fConnected);
            if (winEr != ERROR_SUCCESS)
            {
                WARN(("VBoxTray: (WDDM) Failed vboxDispIfQueryDisplayConnection winEr %d\n", winEr));
                return winEr;
            }

            if (!fConnected)
            {
                WARN(("VBoxTray: (WDDM) Display %d not connected, not expected\n", i));
                fFound = TRUE;
                break;
            }
        }
#endif
        if (!fFound)
            break;
    } while (1);

    return winEr;
}

static DWORD vboxDispIfUpdateModesWDDM(VBOXDISPIF_OP *pOp, uint32_t u32TargetId, const RTRECTSIZE *pSize)
{
    DWORD winEr = ERROR_SUCCESS;
    VBOXDISPIFESCAPE_UPDATEMODES EscData = {0};
    EscData.EscapeHdr.escapeCode = VBOXESC_UPDATEMODES;
    EscData.u32TargetId = u32TargetId;
    EscData.Size = *pSize;

    D3DKMT_ESCAPE EscapeData = {0};
    EscapeData.hAdapter = pOp->Adapter.hAdapter;
#ifdef VBOX_DISPIF_WITH_OPCONTEXT
    /* win8.1 does not allow context-based escapes for display-only mode */
    EscapeData.hDevice = pOp->Device.hDevice;
    EscapeData.hContext = pOp->Context.hContext;
#endif
    EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
    EscapeData.Flags.HardwareAccess = 1;
    EscapeData.pPrivateDriverData = &EscData;
    EscapeData.PrivateDriverDataSize = sizeof (EscData);

    NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
    if (NT_SUCCESS(Status))
        winEr = ERROR_SUCCESS;
    else
    {
        WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_UPDATEMODES failed Status 0x%x\n", Status));
        winEr = ERROR_GEN_FAILURE;
    }

    winEr =  vboxDispIfWaitDisplayDataInited(pOp);
    if (winEr != NO_ERROR)
        WARN(("VBoxTray: (WDDM) Failed vboxDispIfWaitDisplayDataInited winEr %d\n", winEr));

    return winEr;
}

DWORD vboxDispIfCancelPendingResizeWDDM(PCVBOXDISPIF const pIf)
{
    Log(("VBoxTray: cancelling pending resize\n"));
    VBoxRrRetryStop();
    return NO_ERROR;
}

static DWORD vboxDispIfWddmResizeDisplayVista(DEVMODE *paDeviceModes, DISPLAY_DEVICE *paDisplayDevices, DWORD cDevModes, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup)
{
    /* Without this, Windows will not ask the miniport for its
     * mode table but uses an internal cache instead.
     */
    for (DWORD i = 0; i < cDevModes; i++)
    {
        DEVMODE tempDevMode;
        ZeroMemory (&tempDevMode, sizeof (tempDevMode));
        tempDevMode.dmSize = sizeof(DEVMODE);
        EnumDisplaySettings((LPSTR)paDisplayDevices[i].DeviceName, 0xffffff, &tempDevMode);
        Log(("VBoxTray: ResizeDisplayDevice: EnumDisplaySettings last error %d\n", GetLastError ()));
    }

    DWORD winEr = EnableAndResizeDispDev(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, paDeviceModes[iChangedMode].dmPelsWidth, paDeviceModes[iChangedMode].dmPelsHeight,
            paDeviceModes[iChangedMode].dmBitsPerPel, paDeviceModes[iChangedMode].dmPosition.x, paDeviceModes[iChangedMode].dmPosition.y, fEnable, fExtDispSup);
    if (winEr != NO_ERROR)
        WARN(("VBoxTray: (WDDM) Failed EnableAndResizeDispDev winEr %d\n", winEr));

    return winEr;
}

static DWORD vboxDispIfResizePerform(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
{
    DWORD winEr;
    if (pIf->enmMode > VBOXDISPIF_MODE_WDDM)
    {
        winEr = vboxDispIfWddmResizeDisplay(pIf, iChangedMode, fEnable, paDisplayDevices, paDeviceModes, cDevModes);
        if (winEr != NO_ERROR)
            WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplay winEr %d\n", winEr));
    }
    else
    {
        winEr = vboxDispIfWddmResizeDisplayVista(paDeviceModes, paDisplayDevices, cDevModes, iChangedMode, fEnable, fExtDispSup);
        if (winEr != NO_ERROR)
            WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmResizeDisplayVista winEr %d\n", winEr));
    }
    return winEr;
}

DWORD vboxDispIfResizeModesWDDM(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
{
    DWORD winEr = NO_ERROR;

    Log(("VBoxTray: vboxDispIfResizeModesWDDM iChanged %d cDevModes %d\n", iChangedMode, cDevModes));
    VBoxRrRetryStop();

    VBOXDISPIF_OP Op;

    winEr = vboxDispIfOpBegin(pIf, &Op);
    if (winEr != NO_ERROR)
    {
        WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x", winEr));
        return winEr;
    }

    VBOXWDDM_RECOMMENDVIDPN VidPnData;

    memset(&VidPnData, 0, sizeof (VidPnData));

    uint32_t cElements = 0;

    for (uint32_t i = 0; i < cDevModes; ++i)
    {
        if ((i == iChangedMode) ? fEnable : (paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
        {
            VidPnData.aSources[cElements].Size.cx = paDeviceModes[i].dmPelsWidth;
            VidPnData.aSources[cElements].Size.cy = paDeviceModes[i].dmPelsHeight;
            VidPnData.aTargets[cElements].iSource = cElements;
            ++cElements;
        }
        else
            VidPnData.aTargets[cElements].iSource = -1;
    }

    D3DKMT_INVALIDATEACTIVEVIDPN DdiData = {0};

    DdiData.hAdapter = Op.Adapter.hAdapter;
    DdiData.pPrivateDriverData = &VidPnData;
    DdiData.PrivateDriverDataSize = sizeof (VidPnData);

    NTSTATUS Status = Op.pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTInvalidateActiveVidPn(&DdiData);
    LogFunc(("InvalidateActiveVidPn 0x%08x\n", Status));

    /* Resize displays always to keep the display layout because
     * "the D3DKMTInvalidateActiveVidPn function always resets a multimonitor desktop to the default configuration".
     */
    {
        winEr = NO_ERROR;

        if (fEnable)
        {
            RTRECTSIZE Size;
            Size.cx = paDeviceModes[iChangedMode].dmPelsWidth;
            Size.cy = paDeviceModes[iChangedMode].dmPelsHeight;
            winEr = vboxDispIfUpdateModesWDDM(&Op, iChangedMode, &Size);
            if (winEr != NO_ERROR)
                WARN(("vboxDispIfUpdateModesWDDM failed %d\n", winEr));
        }

        if (winEr == NO_ERROR)
        {
            winEr = vboxDispIfResizePerform(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);

            if (winEr == ERROR_RETRY)
            {
                VBoxRrRetrySchedule(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
                /* just pretend everything is fine so far */
                winEr = NO_ERROR;
            }
        }
    }

    vboxDispIfOpEnd(&Op);

    return winEr;
}

static DWORD vboxDispIfWddmEnableDisplays(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnabled, BOOL fSetTopology, DEVMODE *pDeviceMode)
{
    VBOXDISPIF_WDDM_DISPCFG DispCfg;

    DWORD winEr;
    int iPath;

    winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
        return winEr;
    }

    UINT cChangeIds = 0;
    UINT *pChangeIds = (UINT*)alloca(cIds * sizeof (*pChangeIds));
    if (!pChangeIds)
    {
        WARN(("VBoxTray: (WDDM) Failed to alloc change ids\n"));
        winEr = ERROR_OUTOFMEMORY;
        goto done;
    }

    for (UINT i = 0; i < cIds; ++i)
    {
        UINT Id = pIds[i];
        bool fIsDup = false;
        for (UINT j = 0; j < cChangeIds; ++j)
        {
            if (pChangeIds[j] == Id)
            {
                fIsDup = true;
                break;
            }
        }

        if (fIsDup)
            continue;

        iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);

        if (!((iPath >= 0) && (DispCfg.pPathInfoArray[iPath].flags & DISPLAYCONFIG_PATH_ACTIVE)) != !fEnabled)
        {
            pChangeIds[cChangeIds] = Id;
            ++cChangeIds;
        }
    }

    if (cChangeIds == 0)
    {
        Log(("VBoxTray: (WDDM) vboxDispIfWddmEnableDisplay: settings are up to date\n"));
        winEr = ERROR_SUCCESS;
        goto done;
    }

    /* we want to set primary for every disabled for non-topoly mode only */
    winEr = vboxDispIfWddmDcSettingsIncludeAllTargets(&DispCfg);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsIncludeAllTargets winEr %d\n", winEr));
        return winEr;
    }

    if (fSetTopology)
        vboxDispIfWddmDcSettingsInvalidateModeIndeces(&DispCfg);

    for (UINT i = 0; i < cChangeIds; ++i)
    {
        UINT Id = pChangeIds[i];
        /* re-query paths */
        iPath = vboxDispIfWddmDcSearchPath(&DispCfg, -1, Id);
        if (iPath < 0)
        {
            WARN(("VBoxTray: (WDDM) path index not found while it should"));
            winEr = ERROR_GEN_FAILURE;
            goto done;
        }

        winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, pDeviceMode, !fEnabled || fSetTopology, fEnabled);
        if (winEr != ERROR_SUCCESS)
        {
            WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
            goto done;
        }
    }

    if (!fSetTopology)
        vboxDispIfWddmDcSettingsAttachDisbledToPrimary(&DispCfg);

#if 0
    /* ensure the zero-index (primary) screen is enabled */
    iPath = vboxDispIfWddmDcSearchPath(&DispCfg, 0, 0);
    if (iPath < 0)
    {
        WARN(("VBoxTray: (WDDM) path index not found while it should"));
        winEr = ERROR_GEN_FAILURE;
        goto done;
    }

    winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, /* just re-use device node here*/ pDeviceMode, fSetTopology, TRUE);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate winEr %d\n", winEr));
        goto done;
    }
#endif

    UINT fSetFlags = !fSetTopology ? (SDC_USE_SUPPLIED_DISPLAY_CONFIG) : (SDC_ALLOW_PATH_ORDER_CHANGES | SDC_TOPOLOGY_SUPPLIED);
    winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
    if (winEr != ERROR_SUCCESS)
    {
        if (!fSetTopology)
        {
            WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet validation failed winEr, trying with changes %d\n", winEr));
            fSetFlags |= SDC_ALLOW_CHANGES;
        }
        else
        {
            Log(("VBoxTray: (WDDM) vboxDispIfWddmDcSet topology validation failed winEr %d\n", winEr));
            goto done;
        }
    }

    if (!fSetTopology)
        fSetFlags |= SDC_SAVE_TO_DATABASE;

    winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_APPLY);
    if (winEr != ERROR_SUCCESS)
        WARN(("VBoxTray: (WDDM) vboxDispIfWddmDcSet apply failed winEr %d\n", winEr));

done:
    vboxDispIfWddmDcTerm(&DispCfg);

    return winEr;
}

static DWORD vboxDispIfWddmEnableDisplaysTryingTopology(PCVBOXDISPIF const pIf, UINT cIds, UINT *pIds, BOOL fEnable)
{
    DWORD winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, FALSE, NULL);
    if (winEr != ERROR_SUCCESS)
    {
        if (fEnable)
            WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
        else
            Log(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
        winEr = vboxDispIfWddmEnableDisplays(pIf, cIds, pIds, fEnable, TRUE, NULL);
        if (winEr != ERROR_SUCCESS)
            WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplay mode winEr %d\n", winEr));
    }

    return winEr;
}

static DWORD vboxDispIfWddmResizeDisplay(PCVBOXDISPIF const pIf, UINT Id, BOOL fEnable, DISPLAY_DEVICE * paDisplayDevices, DEVMODE *paDeviceMode, UINT devModes)
{
    VBOXDISPIF_WDDM_DISPCFG DispCfg;
    DWORD winEr;
    int iPath;

    winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate\n"));
        return winEr;
    }

    iPath = vboxDispIfWddmDcSearchActivePath(&DispCfg, Id, Id);

    if (iPath < 0)
    {
        vboxDispIfWddmDcTerm(&DispCfg);

        if (!fEnable)
        {
            /* nothing to be done here, just leave */
            return ERROR_SUCCESS;
        }

        winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
        if (winEr != ERROR_SUCCESS)
        {
            WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
            return winEr;
        }

        winEr = vboxDispIfWddmDcCreate(&DispCfg, QDC_ONLY_ACTIVE_PATHS);
        if (winEr != ERROR_SUCCESS)
        {
            WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcCreate winEr %d\n", winEr));
            return winEr;
        }

        iPath = vboxDispIfWddmDcSearchPath(&DispCfg, Id, Id);
        if (iPath < 0)
        {
            WARN(("VBoxTray: (WDDM) path (%d) is still disabled, going to retry winEr %d\n", winEr));
            vboxDispIfWddmDcTerm(&DispCfg);
            return ERROR_RETRY;
        }
    }

    Assert(iPath >= 0);

    if (!fEnable)
    {
        /* need to disable it, and we are done */
        vboxDispIfWddmDcTerm(&DispCfg);

        winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pIf, 1, &Id, fEnable);
        if (winEr != ERROR_SUCCESS)
        {
            WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmEnableDisplaysTryingTopology winEr %d\n", winEr));
            return winEr;
        }

        return winEr;
    }

    Assert(fEnable);

    winEr = vboxDispIfWddmDcSettingsUpdate(&DispCfg, iPath, &paDeviceMode[Id], FALSE, fEnable);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray: (WDDM) Failed vboxDispIfWddmDcSettingsUpdate\n"));
        vboxDispIfWddmDcTerm(&DispCfg);
        return winEr;
    }

    UINT fSetFlags = SDC_USE_SUPPLIED_DISPLAY_CONFIG;
    winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_VALIDATE);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
        fSetFlags |= SDC_ALLOW_CHANGES;
    }

    winEr = vboxDispIfWddmDcSet(&DispCfg, fSetFlags | SDC_SAVE_TO_DATABASE | SDC_APPLY);
    if (winEr != ERROR_SUCCESS)
    {
        WARN(("VBoxTray:(WDDM) pfnSetDisplayConfig Failed to validate winEr %d.\n", winEr));
    }

    vboxDispIfWddmDcTerm(&DispCfg);

    return winEr;
}

#endif /* VBOX_WITH_WDDM */

DWORD VBoxDispIfResizeModes(PCVBOXDISPIF const pIf, UINT iChangedMode, BOOL fEnable, BOOL fExtDispSup, DISPLAY_DEVICE *paDisplayDevices, DEVMODE *paDeviceModes, UINT cDevModes)
{
    switch (pIf->enmMode)
    {
        case VBOXDISPIF_MODE_XPDM_NT4:
            return ERROR_NOT_SUPPORTED;
        case VBOXDISPIF_MODE_XPDM:
            return ERROR_NOT_SUPPORTED;
#ifdef VBOX_WITH_WDDM
        case VBOXDISPIF_MODE_WDDM:
        case VBOXDISPIF_MODE_WDDM_W7:
            return vboxDispIfResizeModesWDDM(pIf, iChangedMode, fEnable, fExtDispSup, paDisplayDevices, paDeviceModes, cDevModes);
#endif
        default:
            WARN((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
            return ERROR_INVALID_PARAMETER;
    }
}

DWORD VBoxDispIfCancelPendingResize(PCVBOXDISPIF const pIf)
{
    switch (pIf->enmMode)
    {
        case VBOXDISPIF_MODE_XPDM_NT4:
            return NO_ERROR;
        case VBOXDISPIF_MODE_XPDM:
            return NO_ERROR;
#ifdef VBOX_WITH_WDDM
        case VBOXDISPIF_MODE_WDDM:
        case VBOXDISPIF_MODE_WDDM_W7:
            return vboxDispIfCancelPendingResizeWDDM(pIf);
#endif
        default:
            WARN((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
            return ERROR_INVALID_PARAMETER;
    }
}

static DWORD vboxDispIfConfigureTargetsWDDM(VBOXDISPIF_OP *pOp, uint32_t *pcConnected)
{
    VBOXDISPIFESCAPE EscapeHdr = {0};
    EscapeHdr.escapeCode = VBOXESC_CONFIGURETARGETS;
    EscapeHdr.u32CmdSpecific = 0;

    D3DKMT_ESCAPE EscapeData = {0};
    EscapeData.hAdapter = pOp->Adapter.hAdapter;
#ifdef VBOX_DISPIF_WITH_OPCONTEXT
    /* win8.1 does not allow context-based escapes for display-only mode */
    EscapeData.hDevice = pOp->Device.hDevice;
    EscapeData.hContext = pOp->Context.hContext;
#endif
    EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
    EscapeData.Flags.HardwareAccess = 1;
    EscapeData.pPrivateDriverData = &EscapeHdr;
    EscapeData.PrivateDriverDataSize = sizeof (EscapeHdr);

    NTSTATUS Status = pOp->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
    if (NT_SUCCESS(Status))
    {
        if (pcConnected)
            *pcConnected = EscapeHdr.u32CmdSpecific;
        return NO_ERROR;
    }
    WARN(("VBoxTray: pfnD3DKMTEscape VBOXESC_CONFIGURETARGETS failed Status 0x%x\n", Status));
    return Status;
}

static DWORD vboxDispIfResizeStartedWDDMOp(VBOXDISPIF_OP *pOp)
{
    DWORD NumDevices = VBoxGetDisplayConfigCount();
    if (NumDevices == 0)
    {
        WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
        return ERROR_GEN_FAILURE;
    }

    DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
    DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
    DWORD DevNum = 0;
    DWORD DevPrimaryNum = 0;

    DWORD winEr = VBoxGetDisplayConfig(NumDevices, &DevPrimaryNum, &DevNum, paDisplayDevices, paDeviceModes);
    if (winEr != NO_ERROR)
    {
        WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed, %d\n", winEr));
        return winEr;
    }

    if (NumDevices != DevNum)
        WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != DevNum(%d)\n", NumDevices, DevNum));

    uint32_t cConnected = 0;
    winEr = vboxDispIfConfigureTargetsWDDM(pOp, &cConnected);
    if (winEr != NO_ERROR)
    {
        WARN(("VBoxTray: vboxDispIfConfigureTargetsWDDM failed winEr 0x%x\n", winEr));
        return winEr;
    }

    if (!cConnected)
    {
        Log(("VBoxTray: all targets already connected, nothing to do\n"));
        return NO_ERROR;
    }

    winEr = vboxDispIfWaitDisplayDataInited(pOp);
    if (winEr != NO_ERROR)
        WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWaitDisplayDataInited failed winEr 0x%x\n", winEr));

    DWORD NewNumDevices = VBoxGetDisplayConfigCount();
    if (NewNumDevices == 0)
    {
        WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: Zero devices found\n"));
        return ERROR_GEN_FAILURE;
    }

    if (NewNumDevices != NumDevices)
        WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NumDevices(%d) != NewNumDevices(%d)\n", NumDevices, NewNumDevices));

    DISPLAY_DEVICE *paNewDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NewNumDevices);
    DEVMODE *paNewDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NewNumDevices);
    DWORD NewDevNum = 0;
    DWORD NewDevPrimaryNum = 0;

    winEr = VBoxGetDisplayConfig(NewNumDevices, &NewDevPrimaryNum, &NewDevNum, paNewDisplayDevices, paNewDeviceModes);
    if (winEr != NO_ERROR)
    {
        WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: VBoxGetDisplayConfig failed for new devices, %d\n", winEr));
        return winEr;
    }

    if (NewNumDevices != NewDevNum)
        WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: NewNumDevices(%d) != NewDevNum(%d)\n", NewNumDevices, NewDevNum));

    DWORD minDevNum = RT_MIN(DevNum, NewDevNum);
    UINT *pIds = (UINT*)alloca (sizeof (UINT) * minDevNum);
    UINT cIds = 0;
    for (DWORD i = 0; i < minDevNum; ++i)
    {
        if ((paNewDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE)
                && !(paDisplayDevices[i].StateFlags & DISPLAY_DEVICE_ACTIVE))
        {
            pIds[cIds] = i;
            ++cIds;
        }
    }

    if (!cIds)
    {
        /* this is something we would not regularly expect */
        WARN(("VBoxTray: all targets already have proper config, nothing to do\n"));
        return NO_ERROR;
    }

    if (pOp->pIf->enmMode > VBOXDISPIF_MODE_WDDM)
    {
        winEr = vboxDispIfWddmEnableDisplaysTryingTopology(pOp->pIf, cIds, pIds, FALSE);
        if (winEr != NO_ERROR)
            WARN(("VBoxTray: vboxDispIfWddmEnableDisplaysTryingTopology failed to record current settings, %d, ignoring\n", winEr));
    }
    else
    {
        for (DWORD i = 0; i < cIds; ++i)
        {
            winEr = vboxDispIfWddmResizeDisplayVista(paNewDeviceModes, paNewDisplayDevices, NewDevNum, i, FALSE, TRUE);
            if (winEr != NO_ERROR)
                WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp: vboxDispIfWddmResizeDisplayVista failed winEr 0x%x\n", winEr));
        }
    }

    return winEr;
}

static DWORD vboxDispIfResizeStartedWDDM(PCVBOXDISPIF const pIf)
{
    VBOXDISPIF_OP Op;

    DWORD winEr = vboxDispIfOpBegin(pIf, &Op);
    if (winEr != NO_ERROR)
    {
        WARN(("VBoxTray: vboxDispIfOpBegin failed winEr 0x%x\n", winEr));
        return winEr;
    }

    winEr = vboxDispIfResizeStartedWDDMOp(&Op);
    if (winEr != NO_ERROR)
    {
        WARN(("VBoxTray: vboxDispIfResizeStartedWDDMOp failed winEr 0x%x\n", winEr));
    }

    vboxDispIfOpEnd(&Op);

    return winEr;
}

DWORD VBoxDispIfResizeStarted(PCVBOXDISPIF const pIf)
{
    switch (pIf->enmMode)
    {
        case VBOXDISPIF_MODE_XPDM_NT4:
            return NO_ERROR;
        case VBOXDISPIF_MODE_XPDM:
            return NO_ERROR;
#ifdef VBOX_WITH_WDDM
        case VBOXDISPIF_MODE_WDDM:
        case VBOXDISPIF_MODE_WDDM_W7:
            return vboxDispIfResizeStartedWDDM(pIf);
#endif
        default:
            WARN((__FUNCTION__": unknown mode (%d)\n", pIf->enmMode));
            return ERROR_INVALID_PARAMETER;
    }
}

static DWORD vboxDispIfSwitchToXPDM_NT4(PVBOXDISPIF pIf)
{
    return NO_ERROR;
}

static DWORD vboxDispIfSwitchToXPDM(PVBOXDISPIF pIf)
{
    DWORD err = NO_ERROR;
    AssertBreakpoint();
    OSVERSIONINFO OSinfo;
    OSinfo.dwOSVersionInfoSize = sizeof (OSinfo);
    GetVersionEx (&OSinfo);
    if (OSinfo.dwMajorVersion >= 5)
    {
        HMODULE hUser = GetModuleHandle("user32.dll");
        if (NULL != hUser)
        {
            bool bSupported = true;
            *(uintptr_t *)&pIf->modeData.xpdm.pfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
            Log((__FUNCTION__": pfnChangeDisplaySettingsEx = %p\n", pIf->modeData.xpdm.pfnChangeDisplaySettingsEx));
            bSupported &= !!(pIf->modeData.xpdm.pfnChangeDisplaySettingsEx);

            if (!bSupported)
            {
                WARN((__FUNCTION__": pfnChangeDisplaySettingsEx function pointer failed to initialize\n"));
                err = ERROR_NOT_SUPPORTED;
            }
        }
        else
        {
            WARN((__FUNCTION__": failed to get USER32 handle, err (%d)\n", GetLastError()));
            err = ERROR_NOT_SUPPORTED;
        }
    }
    else
    {
        WARN((__FUNCTION__": can not switch to VBOXDISPIF_MODE_XPDM, because os is not >= w2k\n"));
        err = ERROR_NOT_SUPPORTED;
    }

    return err;
}

DWORD VBoxDispIfSwitchMode(PVBOXDISPIF pIf, VBOXDISPIF_MODE enmMode, VBOXDISPIF_MODE *penmOldMode)
{
    /* @todo: may need to addd synchronization in case we want to change modes dynamically
     * i.e. currently the mode is supposed to be initialized once on service initialization */
    if (penmOldMode)
        *penmOldMode = pIf->enmMode;

    if (enmMode == pIf->enmMode)
        return NO_ERROR;

#ifdef VBOX_WITH_WDDM
    if (pIf->enmMode >= VBOXDISPIF_MODE_WDDM)
    {
        vboxDispIfWddmTerm(pIf);

        vboxDispKmtCallbacksTerm(&pIf->modeData.wddm.KmtCallbacks);
    }
#endif

    DWORD err = NO_ERROR;
    switch (enmMode)
    {
        case VBOXDISPIF_MODE_XPDM_NT4:
            Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM_NT4\n"));
            err = vboxDispIfSwitchToXPDM_NT4(pIf);
            if (err == NO_ERROR)
            {
                Log((__FUNCTION__": successfully switched to XPDM_NT4 mode\n"));
                pIf->enmMode = VBOXDISPIF_MODE_XPDM_NT4;
            }
            else
                WARN((__FUNCTION__": failed to switch to XPDM_NT4 mode, err (%d)\n", err));
            break;
        case VBOXDISPIF_MODE_XPDM:
            Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_XPDM\n"));
            err = vboxDispIfSwitchToXPDM(pIf);
            if (err == NO_ERROR)
            {
                Log((__FUNCTION__": successfully switched to XPDM mode\n"));
                pIf->enmMode = VBOXDISPIF_MODE_XPDM;
            }
            else
                WARN((__FUNCTION__": failed to switch to XPDM mode, err (%d)\n", err));
            break;
#ifdef VBOX_WITH_WDDM
        case VBOXDISPIF_MODE_WDDM:
        {
            Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM\n"));
            err = vboxDispIfSwitchToWDDM(pIf);
            if (err == NO_ERROR)
            {
                Log((__FUNCTION__": successfully switched to WDDM mode\n"));
                pIf->enmMode = VBOXDISPIF_MODE_WDDM;
            }
            else
                WARN((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
            break;
        }
        case VBOXDISPIF_MODE_WDDM_W7:
        {
            Log((__FUNCTION__": request to switch to VBOXDISPIF_MODE_WDDM_W7\n"));
            err = vboxDispIfSwitchToWDDM_W7(pIf);
            if (err == NO_ERROR)
            {
                Log((__FUNCTION__": successfully switched to WDDM mode\n"));
                pIf->enmMode = VBOXDISPIF_MODE_WDDM_W7;
            }
            else
                WARN((__FUNCTION__": failed to switch to WDDM mode, err (%d)\n", err));
            break;
        }
#endif
        default:
            err = ERROR_INVALID_PARAMETER;
            break;
    }
    return err;
}

static DWORD vboxDispIfSeamlesCreateWDDM(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
{
    HRESULT hr = vboxDispKmtOpenAdapter(&pIf->modeData.wddm.KmtCallbacks, &pSeamless->modeData.wddm.Adapter);
    if (SUCCEEDED(hr))
    {
#ifdef VBOX_DISPIF_WITH_OPCONTEXT
        hr = vboxDispKmtCreateDevice(&pSeamless->modeData.wddm.Adapter, &pSeamless->modeData.wddm.Device);
        if (SUCCEEDED(hr))
        {
            hr = vboxDispKmtCreateContext(&pSeamless->modeData.wddm.Device, &pSeamless->modeData.wddm.Context, VBOXWDDM_CONTEXT_TYPE_CUSTOM_DISPIF_SEAMLESS,
                    0, 0, hEvent, 0ULL);
            if (SUCCEEDED(hr))
#endif
                return ERROR_SUCCESS;
#ifdef VBOX_DISPIF_WITH_OPCONTEXT
            else
                WARN(("VBoxTray: vboxDispKmtCreateContext failed hr 0x%x", hr));

            vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
        }
        else
            WARN(("VBoxTray: vboxDispKmtCreateDevice failed hr 0x%x", hr));

        vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);
#endif
    }

    return hr;
}

static DWORD vboxDispIfSeamlesTermWDDM(VBOXDISPIF_SEAMLESS *pSeamless)
{
#ifdef VBOX_DISPIF_WITH_OPCONTEXT
    vboxDispKmtDestroyContext(&pSeamless->modeData.wddm.Context);
    vboxDispKmtDestroyDevice(&pSeamless->modeData.wddm.Device);
#endif
    vboxDispKmtCloseAdapter(&pSeamless->modeData.wddm.Adapter);

    return NO_ERROR;
}

static DWORD vboxDispIfSeamlesSubmitWDDM(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
{
    D3DKMT_ESCAPE EscapeData = {0};
    EscapeData.hAdapter = pSeamless->modeData.wddm.Adapter.hAdapter;
#ifdef VBOX_DISPIF_WITH_OPCONTEXT
    EscapeData.hDevice = pSeamless->modeData.wddm.Device.hDevice;
    EscapeData.hContext = pSeamless->modeData.wddm.Context.hContext;
#endif
    EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
    /*EscapeData.Flags.HardwareAccess = 1;*/
    EscapeData.pPrivateDriverData = pData;
    EscapeData.PrivateDriverDataSize = VBOXDISPIFESCAPE_SIZE(cbData);

    NTSTATUS Status = pSeamless->pIf->modeData.wddm.KmtCallbacks.pfnD3DKMTEscape(&EscapeData);
    if (NT_SUCCESS(Status))
        return ERROR_SUCCESS;

    WARN(("VBoxTray: pfnD3DKMTEscape Seamless failed Status 0x%x\n", Status));
    return Status;
}

DWORD VBoxDispIfSeamlesCreate(PCVBOXDISPIF const pIf, VBOXDISPIF_SEAMLESS *pSeamless, HANDLE hEvent)
{
    memset(pSeamless, 0, sizeof (*pSeamless));
    pSeamless->pIf = pIf;

    switch (pIf->enmMode)
    {
        case VBOXDISPIF_MODE_XPDM_NT4:
        case VBOXDISPIF_MODE_XPDM:
            return NO_ERROR;
#ifdef VBOX_WITH_WDDM
        case VBOXDISPIF_MODE_WDDM:
        case VBOXDISPIF_MODE_WDDM_W7:
            return vboxDispIfSeamlesCreateWDDM(pIf, pSeamless, hEvent);
#endif
        default:
            WARN(("VBoxTray: VBoxDispIfSeamlesCreate: invalid mode %d\n", pIf->enmMode));
            return ERROR_INVALID_PARAMETER;
    }
}

DWORD VBoxDispIfSeamlesTerm(VBOXDISPIF_SEAMLESS *pSeamless)
{
    PCVBOXDISPIF const pIf = pSeamless->pIf;
    DWORD winEr;
    switch (pIf->enmMode)
    {
        case VBOXDISPIF_MODE_XPDM_NT4:
        case VBOXDISPIF_MODE_XPDM:
            winEr = NO_ERROR;
            break;
#ifdef VBOX_WITH_WDDM
        case VBOXDISPIF_MODE_WDDM:
        case VBOXDISPIF_MODE_WDDM_W7:
            winEr = vboxDispIfSeamlesTermWDDM(pSeamless);
            break;
#endif
        default:
            WARN(("VBoxTray: VBoxDispIfSeamlesTerm: invalid mode %d\n", pIf->enmMode));
            winEr = ERROR_INVALID_PARAMETER;
            break;
    }

    if (winEr == NO_ERROR)
        memset(pSeamless, 0, sizeof (*pSeamless));

    return winEr;
}

DWORD VBoxDispIfSeamlesSubmit(VBOXDISPIF_SEAMLESS *pSeamless, VBOXDISPIFESCAPE *pData, int cbData)
{
    PCVBOXDISPIF const pIf = pSeamless->pIf;

    if (pData->escapeCode != VBOXESC_SETVISIBLEREGION)
    {
        WARN(("VBoxTray: invalid escape code for Seamless submit %d\n", pData->escapeCode));
        return ERROR_INVALID_PARAMETER;
    }

    switch (pIf->enmMode)
    {
        case VBOXDISPIF_MODE_XPDM_NT4:
        case VBOXDISPIF_MODE_XPDM:
            return VBoxDispIfEscape(pIf, pData, cbData);
#ifdef VBOX_WITH_WDDM
        case VBOXDISPIF_MODE_WDDM:
        case VBOXDISPIF_MODE_WDDM_W7:
            return vboxDispIfSeamlesSubmitWDDM(pSeamless, pData, cbData);
#endif
        default:
            WARN(("VBoxTray: VBoxDispIfSeamlesSubmit: invalid mode %d\n", pIf->enmMode));
            return ERROR_INVALID_PARAMETER;
    }
}


I did a blog two weeks ago about getting back to working out again. Unfortunately, I was sidelined by my eyebrows. Yes, you read that correctly. I couldn't workout because of my eyebrows.
I had an appointment the next day to have my eyebrows microbladed. It is a type of tattoo, so I couldn't get them wet for ten days. I've never had a tattoo before, so I didn't know that keeping it dry was going to be crucial to the end results.
I went to a salon-type of place, not a tattoo parlor. The procedure was much less painful than I expected. If you consider this, it is vitally important that you find out if the place where you are doing it uses the proper pigments because they can fade to green if you go to the wrong place. I was referred by a doctor who was familiar with the pigments and results from this salon. Another important thing to find out is if they use a numbing cream first. That is the key to not having a painful experience. The technician told me that some people do not numb at all, so you feel everything.
There are two huge advantages to microblading. The first is that I don't have to spend time trying to draw them on evenly. The second is that I have a template to pluck my eyebrows, so I don't have to worry about over-plucking or getting the shape just right every time. Trust me, it's time-consuming. I will go back in a month to have them touched up. I noticed that I have a slightly higher point on one side that she can fix.
The end result is awesome because they tattoo individual hairs instead of a blob of color. If you look closely at the last picture on the inside corners near my nose, you can see a couple of the individual hair strokes that were tattooed on.
My eyebrows became sparse because I have hypothyroidism. This is the before pictures of both sides. There wasn't much to work with, so I had to draw them on every day.
This is what it looked like in the middle of the process. I know that it looks a little Groucho Marx-ish, but the end result was fantastic.
Immediately after the procedure, I was a little red. It felt a bit like a sunburn. I had to refrain from using any kind of lightening or acne products on my face while it healed. They are also much darker here than the end result.
By day 5, they were beginning to show what they were going to look like.
Now they are fully healed, so I can get back to working out again.
I paid $350, plus a tip and will need to go back for a touch-up that will cost another $100. It is well worth it to me. I spent a lot of time and money on Anastasia Brow Whiz ($21) and Dipbrow Pomade ($18). I won't have to do that ever again. I'll go back once a year for maintenance.


The International Workshop on Mobile and Cloud Computing (iw-mcc) 2012 being organized by Techno India NJR, and with the joint efforts of IEEE India Educational Society from 4th-5th Dec 2012 had its first day today. Inaugurated by John Walz, president, IEEE Computer Society, the workshop was followed by his Keynote speech. The workshop started with a houseful session by Madhukar Dubey, CEO, Fusion eSolutions LLC, USA over basics of Cloud Computing and Innovations, followed by speech of Gaurav Mantri founder, Cerebrata Softwares and Windows Azure MVP (Most Valuable Professional) over Windows Azure details. In the later session, Ravi Singhal (IBM AIX Expert) took a session over Data Warehousing and Application for Datacenter, and gave students a hands-on session on the IBM AIX servers. Mr. Ananya Singhal, Group Head IT & Infrastructure, Secure meters was the Guest of Honour.
Previous articleHaving Fever..?? CAUTION – It Can be Dengue!


The article/interview that was published in the MCD magazine earlier this month, is, of course, a shortened version of a very (very!) long interview I gave. Laurent Diouf, the wonderful chief editor of MCD, and I decided that it would be a waste to just trash the whole thing, and thus we decided to publish it here.
01_ first, can you describe your background, influences, and also why you choose the name "glitterbug"…?
My love for electronic music, and thus my first influences and exposure to it, stem from the late 80s rave and acid scene, at least when speaking about electronic dance music. I was a very vivid party goer already in my early youth in 1986/87, and was also making music at that time (my instruments then were the flute and drums, but I was mostly playing in jazz bands and the school big band). Back then I didn't have these different musical worlds connected, nor did I realize they could even meet. I was sort of living in three different musical worlds that never ever really overlapped: I had my band/jazz life as a very young musician, my love for acid music and raves, and in addition was listening to and admiring totally different music: 80s wave, experimental music, contemporary composition, experimental indie rock, things like that, but always with a focus on the more touching, emotional and melancholic things.
After the late 80s and three years of heavy raving, my interest in electronic dance music became smaller until it was sparked again in 1994 during a performance by not-so-famous-yet Jeff Mills, who gave a show in a legendary Cologne Club called '42'- in front of maybe 40 people… this is where my ongoing and deep love for Techno comes from. This was also the point where I bought my first two Technics turntables and started buying DJ vinyl. Two years later, in 1996, I was DJing at my first parties. During the 90s, the scene here wasn't yet so 'specialized' or narrow: the experimental-music people went to techno parties, there were "chill out rooms" in which abstract and eclectic music was played, and everybody was hanging out with everybody. This very special breeding ground in those years, with an approach that "anything goes", was very important for my later baby steps into producing music myself.
In the early 90s I also started basic freelance work for public radio stations in Germany, mostly in the field of 'sound design' (well, the term didn't exist back then) for radio plays, later working on experimental radio plays of my own, which eventually led to my first equipment purchases in the mid/late 90's. The stuff I was working on back then was mostly more abstract and very experimental, toying around with cheap broken equipment (which was the only stuff that I could afford).
02_ how did you planed and composed your new album, "privilege" ? can we say that it is less "dub", more ambient or introspective than "supershelter" ?
Well, the plan changed over the course of time. All together I worked for something like a year on this album. At first, I wanted to make a totally abstract ambient album, and I started drafting first tracks, but at the same I was working on more techno (and/or house) tracks. After a couple of months, I started to listen to the tracks that I made and realized that my concept didn't work at all: the tracks, regardless of their 'genre', were all related to one another, were following a similar mood and atmosphere, and so I realized that it's pointless to try to separate them. I already had a lot of material, which could have been enough for an album, but I felt it wasn't quite there.
So the second idea was to continue working, and to try to take my creative process out of the studio and to continue working more "on the road", knowing that I would be touring a lot. Since currently I mostly perform live, using a lot of outboard equipment, I had a very basic studio on me all the time… I had a 2 months long "world" tour in 2009, which brought me to places like China, India, Norway, Poland to name just a few. Some of the tracks on the album were drafted during this tour and have quite a few field recordings from those places in them.
So the second approach was to do a double CD album with one studio part and one "on the road" part. This concept I also threw overboard once I started to seriously compile the album. The tracks were not only related, they also told a stringent story regardless of the period in which they were made; so I compiled them accordingly, with my heart and intuition rather than by categorizing them according to when and where I made them.
Speaking of differences and similarities to 'Supershelter' and the general musical direction I took with 'Privilege', I can say that it is much more serious in many ways, less cheerful, more restrained and certainly moodier than 'Supershelter'. But I disagree that it is more "Ambient" then pervious things I have done, since there are quite a few tracks on there which speak a very clear, direct and loud club language (well, we're still speaking Glitterbug here, right?). The effect of feeling that 'Privilege' is more ambient than its predecessor comes mostly from the fact that it is long and that I finally had the chance to span my ideas and tracks over such a long playtime. Nothing is rushed on this album, and I had the freedom to leave plenty 8 or 9 minute long tracks unshortened… This was an amazing new artistic freedom that I could achieve in this project.
'Privilege' also is definitely much more introspective, that's true. It's quite a pensive album, which also reflects on the circumstances of its own existence. During my last international tour I played in places which confronted me with the obscene wealth of opportunities I have in life, and the fact that I can choose to be an artist, a musician, composer or producer (or whatever you might call what I do) is pretty unbelievable. I played in places like Mumbai/ India, where the level of poverty is simply unimaginable. To be invited to Mumbai to play in a fancy club, driving through never-ending slums on the way from the hotel to the venue with equipment in the trunk that is worth enough to feed a small town in India for months is something that left a huge dent in my reception of reality. So yes, 'Privilege' is quite a serious album, but also has very hopeful moments. It's charting new territories in a way; for me, it is like my approach to find new worlds, places and habitats in and through music.
03_ generally speaking, how do you define dub music and more especially how do you describe the connection between dub and minimal-techno/ambient, and also the evolution of this connection/emulation ?
But seriously: this is a tough question for me to answer. My approach to music and also to making music is different from any analytical approach. I don't analyze what I do categorically, as I have a very emotional access to my art and music. The same with my record collection spanning through quite a few thousand vinyls (and a considerable amount of CDs and hard drives): it's all not so much filed under musical categories, but rather moods and atmospheres. This is also how I put together my DJ materials for sets: less by a certain musical category, but more by the feel of the tracks.
04_ as the previous, "privilege" is available on c.sides. please, can you tell us about this structure ? if i well understand, you co-run s.sides with ronni shendar. so this "plateform for electronic music and new media art" is also a kind of arc / bridge between israel (+ palestine) and german 's projects / musicians, artists, etc. ?
c.sides is a lot of things, and all of them carry a very personal signature. I started it (and continued it until today) together with Ronni Shendar, an Israeli photographer and video artist. We met in early 2003 in a German-Israeli artist exchange, and shortly after I came to Israel for my first DJ gigs. The electronic music scene there was under total isolation back then (due to the 2nd Intifada which was at its peak in those days), and we started a process of bringing more international artists, mainly (but not only) from Germany, to Israel and also inviting artists to Germany.
From the beginning, the informal exchange was solely based on mutual interest, on reflecting the different backgrounds, histories, realities and contexts. Obviously, confronting a lot of issues of the 3rd generation after the Holocaust for both the German and the Israeli side, and the realities of the Occupation, the vast social complexities in Israel, questions of art production in periods of war and unrest, and the different socio-economic-political issues both sides had to confront.
Before we even came up with the idea of establishing a more of a formal platform for exchange, something like 15-20 artists from both countries went through these different visits- and Ronni and I realized that there is so much mutual interest that we need to create something bigger, that allows for more people to join.
c.sides is a totally non-commercial platform, and was built from the beginning (2004) as a mixture between an electronic music and media arts festival and sort of an educational program for participating artists.
All artists that we invited over the years came for at least a week to participate in educational tours, lectures and exchanges that we organized for them. We wanted to make sure they can grasp as many perspectives as possible of a complicated place with intertwined struggles. The goal is to send everybody back home with more questions than they came with, and to portray the situation in the Middle East as complex and multi layered as it is for the many different communities that live there.
We are a political festival- but without a political agenda… we oppose easy answers and put our bet on discussing complexities of gray zones in which people actually live and confront rather than simplistic black/white thinking. Besides our major productions in Israel (in the beginning in Jerusalem, these days in Tel Aviv), we have also had various projects and show cases in Europe, and have more cooking up for the future.
To curate and produce a festival like ours is a very challenging subject matter. The current situation in Israel, especially the news of today with the stormed flotilla that was supposed to bring humanitarian aid to Gaza, always pushes us over the cliff when we try to think of how to continue the c.sides festival. But as grief as the situation is, and as horrible and awful, we are still trying to organize something that raises awareness, that questions the status quo of art production, and that widens the perceptional horizons of artists and audiences alike.
05_ what about the c.sides festival ? will you do an edition this year (i don't see infos) ? or in 2011 ? or is it in stand by ?
Well, since c.sides is ran by exactly 2 people (and that is, surprise surprise, Ronni Shendar and me), we can decide on every aspect of what c.sides is and where c.sides is heading. We started the festival as an annual project, but realized already in 2006 that this would not leave any room to breathe for any of our other projects and our individual artistic work.
Since there never was a plan to become festival directors (and nor do we enjoy producing something so crazy as a festival), but rather having a festival that developed out of a need for something like that (there was no such thing in Israel when we started, and by now we are by far the largest festival of its kind in Israel), we try to balance our time between the festival and our other projects, and thus it's a loosely bi-annual project. We are cooking up something for late 2011, but it's way too early to speak about it.
In addition, we do have all the issues that most other festivals internationally are facing these days: lack of funding. The financial crisis hit arts and culture hard, and our festival is sadly no exception being a non-commercial initiative. We try to create something that confronts the context it takes place in, and Israel is a fast changing place, currently with a very right-winged government. This of course has a great effect on our production, specifically making it more and more difficult (or rather virtually impossible) to work with Palestinians in the West Bank or other cooperations we have tried with artists from Egypt or Lebanon. We sadly have to keep the two paths separately for now.
06_ generally speaking, how do you consider the (rare) musical intitiatives relative to some socio/political situations and/or events ? i mean, do you think that the electronic scene has a socio-political consciousness ? and do you think it could be really efficient ?
Well, if I wouldn't believe in some possible artistic contribution to make the world a better place, I probably wouldn't co-run a festival like c.sides. I talked about a few of these things above.
Generally speaking, I think that the electronic music scene has to reclaim some of its roots. Especially playing a lot of festivals and club events as an artist myself, I meet a lot of colleagues that seem to have forgotten that we once were part of a movement, of a culture, and that there is (and should be!) more to what we do than just the party itself, the Champaign brand the promoter chooses, and the quality of drugs available. We live in a very very VERY privileged situation, and well, yes, I do think that this comes with certain obligations.
I am not a friend of over exposing content where there is none. I am also not a big fan of hollow slogans and simple answers. But in my reception, electronic music should always carry the liberating elements that House Music was born with, and for me, my artistic process of creating music always also has to do with creating parallel universes, additional habitats, and somewhat of trying to create a better world. In tiny pieces, and tiny contributions, but at least we should try to make our privileges as artist beneficial for others too.
07_ by the way, can you tell us about the electronic music scene in israel — we only know the trance-goa movement but (almost) not the minimal and experimental scene — and also in cologne nowadays ?
Uf! You want me to write a book??
I am and have been only present in small parts of the electronic music scene in Israel, and it has been changing a lot in the past few years.
In a nutshell, when I first came to Israel in 2003, there was a very small, dedicated (and isolated) experimental electronica scene in Jerusalem, and a very commercial house scene in Tel Aviv. The techno that was played was of the tough fast industrial kind, and when I first played in Israel, the strange, slow, melodic and more minimal music that I played during peak time in clubs was totally unknown, and people were very confused by it in the beginning.
Today Tel Aviv hosts two wonderful clubs for techno, house and wider scopes of electronic dance music (The Block and Barzilay), in addition to smaller independent lines that take place in obscure and changing locations and aside to countless mainstream clubs. The scene has developed and grown quickly! By now every weekend there is at least one leading international act playing at one of these clubs, with a strong connection to Berlin, New York and Detroit.
There are definitely more and more Israelis producing music and also part of the international techno/house scene.
08_ relative to your live-mixes / dj-sets, are you still playing with 3 turntables or/and are you also using digital sources ?
My live performances are based on a hybrid setup with analogue gear and synthesizers, and a computer running the same software as most other computers you find on stage these days, with a vast amount of controllers. I do not touch the computer during the show, but use my controller setup to navigate.
When I DJ, I am always asking for three turntables, but sadly most club setups don't have space for a third turntable in the DJ booth these days. I have been using a hybrid between digital vinyl control systems (in the beginning, I used a MAX/MSP patch for vinyl control called Ms. Pinky, today it's a product of one of the key players in vinyl controlled playback, due to reliability issues) together with vinyl for something like 9 years now, and I enjoy the opportunities I have as a DJ in a setup like that.
09_ you did also some radio shows and/or mix for web-radio (if i'm not wrong). i think radio-shows are may be a sound-universe — a "blind" universe because we don't see the audience — between live-mix and studio work… so, how do you plan/manage your selection for radio ?
Preparing DJ sets for podcasts or for radio shows is allowing for totally different approaches than a DJ set in club. I can allow myself to be less of an entertainer, and can play more with atmosphere. I also have to bear in mind that radio shows are often more of an audible backdrop more than something that is listened to consciously, so try to create something that is emotionally dense yet not too challenging on the ear.
My music has often been described as "visual club music", and I am quite happy with that category. I try to create music that has a certain depth to it, music that takes the listener someplace. I work with a lot of imagination, and creating music in the studio is always a very lonely and isolated task. So standing in a radio studio and playing and mixing music for unknown people in unknown situations out there, to be present in their homes and daily life through the medium of radio is something very magical to me.
10_ i saw that you're also doing performances av (with ronni shendar), installations, b.o./soundtracks, etc. and you also work as curator. so, a few sentences about your "side" projects ?
I am involved in many different things, my club alter ego Glitterbug is only one of them. I am currently working on an abstract score for a more philosophical documentary movie about jails, have been doing collaborations with other visual artists for installations, have been active as a curator for more than a decade… I don't necessarily do these things all the time, but if an interesting project pops up, I am always happy to take the challenge.
Ronni (Shendar) and I have been working together since almost 8 years now, and for us it was just a logical step from curating the festival which deals both with audible and visual digital art, and creating platforms and structures for other artists to translate these philosophies into our own project and art forms – an audio-visual live performance.
Ronni adds a totally new perspective to my live performance. She works only with her own footage, materials and photographs that she manipulates very minimalistically through various programs. She creates a very cinematic language that corresponds with my visual music and that unfolds layers, textures and landscapes of her concurrent world. We try to create a dialogue between our 'worlds', it's really a very joint performance, in some parts inseparable.
From the press sheet regarding our joint show: "In creating their new live performance, Shendar followed on the album's base concepts and themes, drawing upon to explore its desolate landscapes, its uninhibited territories and blurry distant dolor, a further interpretation to her photographs that comprise the album's artwork.
This entry was posted on Wednesday, July 14th, 2010 at 9:08 am and is filed under Press / Reviews.	You can follow any responses to this entry through the RSS 2.0 feed. Responses are currently closed, but you can trackback from your own site.