1

現在、C++ を使用して、GPU (T4、グリッド ライセンス、および仮想ワークステーション グリッド ドライバー) を備えた Windows Server 2019 VM で完全にカスタムの解像度を設定する方法を探しています。

これを達成するために別の方法を試しました。ラップトップでこれを機能させることができますが、GCP VM (または Windows Server の制限) にいくつかの制限があるようです。

ChangeDisplaySettings/ChangeDisplaySettingsEx (winuser.h) を使用してこれを実行しようとしましたが、既知の解像度に変更できますが、カスタムの解像度で動作させることはできません (CDS_ENABLE_UNSAFE_MODE を使用しても)。

DWORD deviceIndex = 0;
DISPLAY_DEVICE displayDevice = { 0 };
displayDevice.cb = sizeof(DISPLAY_DEVICE);

while (EnumDisplayDevices(NULL, deviceIndex, &displayDevice, 0)) {
    deviceIndex++;

    DEVMODE dm = { 0 };
    dm.dmSize = sizeof(DEVMODE);

    DEVMODE finalDm = { 0 };
    finalDm.dmSize = sizeof(DEVMODE);

    //Check if able to retrieve current settings
    if (!EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
        continue;
    }

    //Check if there is a difference in resolution list if UNSAFE_MODE is enabled or not (it seems to not change anything)
    int result = ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, 0, CDS_DISABLE_UNSAFE_MODES, NULL);
    std::cout << "CDS_DISABLE_UNSAFE_MODE" << std::endl;
    if (result == DISP_CHANGE_SUCCESSFUL) {
        for (int i = 0; EnumDisplaySettings(displayDevice.DeviceName, i, &dm) != 0; i++) {
            if (dm.dmBitsPerPel == 32) {
                std::cout << i << ". Found available resolution : " << dm.dmPelsWidth << " x " << dm.dmPelsHeight << " x " << dm.dmBitsPerPel << " @ " << dm.dmDisplayFrequency << std::endl;
            }
        }
    }

    result = ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, 0, CDS_ENABLE_UNSAFE_MODES, NULL);
    std::cout << "CDS_ENABLE_UNSAFE_MODE" << std::endl;
    if (result == DISP_CHANGE_SUCCESSFUL) {
        for (int i = 0; EnumDisplaySettings(displayDevice.DeviceName, i, &dm) != 0; i++) {
            if (dm.dmBitsPerPel == 32) {
                std::cout << i << ". Found available resolution : " << dm.dmPelsWidth << " x " << dm.dmPelsHeight << " x " << dm.dmBitsPerPel << " @ " << dm.dmDisplayFrequency << std::endl;
            }
        }
    }


    std::cout << "Please enter width : ";
    int width, height;
    std::cin >> width;
    std::cout << "Please enter height : ";
    std::cin >> height;

    dm.dmPelsWidth = width;
    dm.dmPelsHeight = height;
    if (width > height) {
        dm.dmDisplayOrientation = DMDO_DEFAULT;
    }
    else {
        dm.dmDisplayOrientation = DMDO_90;
    }
    dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYORIENTATION;

    //result = ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, NULL, CDS_TEST, NULL);
    result = ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, NULL, 0, NULL);

    if (result != DISP_CHANGE_SUCCESSFUL) {
        std::cout << "Impossible to ChangeDisplaySettings" << endl;
    }
    else {
        std::cout << "OK" << endl;
    }

    break;
}

次に、NVAPI を調べます。ここでも同じように、自分の PC で動作させることができますが、GCP VM ではまだ何も動作しません。ローカル PC で NVAPI を作成してカスタム解像度を使用する方法を見つけましたが、もう一度 GCP VM で動作させないでください... (コード例はこちらにあります)

NvAPI_Status result = NVAPI_ERROR;
NvU32 primaryDisplayId = 0;


//Testing resolution
int horizontal = 1920, vertical = 1090;

result = NvAPI_Initialize();

if (result != NVAPI_OK) {
    printf("Could not initialize NvAPI");
    return false;
}

MONITORINFOEX monInfo;
HMONITOR hMon;
const POINT ptZero = { 0, 0 };

// determine the location of the primary monitor
hMon = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
ZeroMemory(&monInfo, sizeof(monInfo));
monInfo.cbSize = sizeof(monInfo);
GetMonitorInfo(hMon, &monInfo);

result = NvAPI_DISP_GetGDIPrimaryDisplayId(&primaryDisplayId);

if (result != NVAPI_OK) {
    printf("Could not get display ID from device");
    NvAPI_Unload();
    return false;
}

NvU32 deviceCount = 0;
NV_CUSTOM_DISPLAY cd[NVAPI_MAX_DISPLAYS] = { 0 };

float refreshRate = 60;
// timing computation (to get timing that suits the changes made)
NV_TIMING_FLAG flag = { 0 };
NV_TIMING_INPUT timing = { 0 };
timing.version = NV_TIMING_INPUT_VER;
timing.height = vertical;
timing.width = horizontal;
timing.rr = refreshRate;
timing.flag = flag;
timing.type = NV_TIMING_OVERRIDE_CVT_RB;

result = NvAPI_DISP_GetTiming(primaryDisplayId, &timing, &cd[0].timing);

if (result != NVAPI_OK) {
    printf("Failed to get timing for display"); // failed to get custom display timing
    NvAPI_Unload();
    return false;
}



cd[0].width = horizontal;
cd[0].height = vertical;
cd[0].xRatio = 1;
cd[0].yRatio = 1;
cd[0].srcPartition = { 0, 0, 1.0, 1.0 };
cd[0].depth = 32;
cd[0].version = NV_CUSTOM_DISPLAY_VER;
cd[0].colorFormat = NV_FORMAT_A8R8G8B8;

//Returns NVAPI_ERROR on GCP but NVAPI_OK on my laptop
result = NvAPI_DISP_TryCustomDisplay(&primaryDisplayId, 1, cd); 

if (result != NVAPI_OK) {
    printf("Could not set custom resolution");
    NvAPI_DISP_RevertCustomDisplayTrial(&primaryDisplayId, 1);
    NvAPI_Unload();
    return false;
}
else {
    NvAPI_DISP_SaveCustomDisplay(&primaryDisplayId, 1, true, true);
}

この部分はラップトップで完全に機能します。新しい動的解像度を使用できます (1920x400、1920x500、1920x600 で動作します) が、GCP VM では機能しません。この部分は次のとおりです。

NvAPI_DISP_TryCustomDisplay(&primaryDisplayId, 1, cd);

常に NVAPI_ERROR を返します

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Video{ RANDOM_ID }\0001\NV_Modes というレジストリ エントリを編集できます。 NVAPI を使用して解像度を追加し、ChangeDisplaySettingsEx 関数を使用してこの解像度を設定できます (GPU ドライバーを再起動するか、Windows を再起動して新たに追加された解像度に変更できるようにする必要があります)。しかし、「dmDisplayOrientation」で遊んで画面を回転できるようにする必要があり、GCP VM でもう一度動作しないようです。 = DMDO_90" (1090x1920も許可しても…)

誰かが方法を見つけた場合、またはこれを行う方法についてアイデアを持っている場合は、それは素晴らしいことです.私は今アイデアを使い果たしています...

4

0 に答える 0