Filter video modes for user choice?

Dear group,

while I have no question about querying the video modes technically, I was wondering if there is an established, known-good strategy for filtering the list of video modes so that it can be presented to the user for his/her choice of a favorite mode.

My current strategy is:

  • ignore red, green, blue bit depths,
  • ignore refresh rate,
  • remove duplicates (resulting from ignores above),
  • remove modes with very low width and height (e.g. less than 800),
  • remove modes with aspect ratio that is different from the physical screen size,
  • but keep at least three modes, even if at low width or mismatching screen size.

As a variation, among modes with common size, the only the refresh rate could be ignored and the mode be kept that has the largest number of red, green, blue bits. Must still remove duplicates, in case the same mode has been reported at various refresh rates.

Well, I was wondering what others were doing?

Best regards,
Carsten

I filter out modes without at least 8 bit RGB (not really required these days since all resolutions have an 8bit RGB context available), combine refresh and remove duplicates. I don’t restrict the number of modes I show though.

Hi Doug,
thanks for your reply!

In the meanwhile, I found a strategy that works well for me:

  • Among modes of the same width, only keep the one whose aspect ratio best matches the aspect ratio of the physical screen. (The resulting list may still have modes with arbitrary a-r.)
  • Optionally prune the result further by only keeping the modes with an a-r that is close to the physical a-r.

Not entirely pure GLFW code, but almost:

std::string glfwMonitorT::getUserChoiceList() const
{
    unsigned int phys_width;
    unsigned int phys_height;

    getPhysicalSize(phys_width, phys_height);

    const float phys_ar = float(phys_width) / float(phys_height);
    int num_modes;
    const GLFWvidmode* modes = glfwGetVideoModes(m_monitor, &num_modes);
    std::vector<GLFWvidmode> ModeList;

    ModeList.reserve(num_modes);
    for (int i = 0; i < num_modes; i++)
        ModeList.push_back(modes[i]);

    std::sort(ModeList.begin(), ModeList.end(), CompareByWidth());

    printModes("All modes, sorted by width", ModeList, phys_ar);

    // Among modes that are of (almost) the same width, keep the one that best matches
    // the aspect-ratio of the physical screen.
    // This also removes duplicates from ignoring the bits per pixel and refresh rate.
    for (size_t i = 0; i < ModeList.size(); i++)
    {
        float mi_ar = float(ModeList[i].width) / float(ModeList[i].height);
        float mi_df = fabs(phys_ar - mi_ar);

        for (size_t j = i + 1; j < ModeList.size(); j++)
        {
            if (abs(ModeList[i].width - ModeList[j].width) < 80)
            {
                const float mj_ar = float(ModeList[j].width) / float(ModeList[j].height);
                const float mj_df = fabs(phys_ar - mj_ar);

                if (mj_df < mi_df)
                {
                    ModeList[i] = ModeList[j];
                    mi_ar = mj_ar;
                    mi_df = mj_df;
                }

                ModeList.erase(ModeList.begin() + j);
                j--;
            }
        }
    }

    printModes("Kept the best match for each width", ModeList, phys_ar);

    // Remove modes with mismatching aspect ratios.
    for (size_t i = 0; i < ModeList.size() && ModeList.size() > 3; i++)
    {
        const float mi_ar = float(ModeList[i].width) / float(ModeList[i].height);
        const float mi_df = fabs(phys_ar - mi_ar);

        if (mi_df >= 0.1f)
        {
            ModeList.erase(ModeList.begin() + i);
            i--;
        }
    }

    printModes("Mismatching aspect ratios removed", ModeList, phys_ar);

    // Assemble result.
    std::string s;

    for (size_t i = 0; i < ModeList.size(); i++)
        s += std::to_string(ModeList[i].width) + " x " + std::to_string(ModeList[i].height) + "\n";

    return s;
}

On my 16:10 screen, this yields:

All modes, sorted by width:    (physical monitor a-r is 1.602)
     320 *  200, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
     320 *  200, 16:10.0 (1.600 0.002), 8 8 8, 60Hz
     320 *  240, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
     320 *  240, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
     400 *  300, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
     400 *  300, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
     512 *  384, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
     512 *  384, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
     640 *  400, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
     640 *  400, 16:10.0 (1.600 0.002), 8 8 8, 60Hz
     640 *  480, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
     640 *  480, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
     720 *  480, 16:10.7 (1.500 0.102), 8 8 8, 59Hz
     720 *  480, 16:10.7 (1.500 0.102), 8 8 8, 60Hz
     800 *  600, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
     800 *  600, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
    1024 *  768, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
    1024 *  768, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
    1152 *  864, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
    1152 *  864, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
    1280 *  600, 16: 7.5 (2.133 -0.531), 8 8 8, 59Hz
    1280 *  600, 16: 7.5 (2.133 -0.531), 8 8 8, 60Hz
    1280 *  720, 16: 9.0 (1.778 -0.176), 8 8 8, 59Hz
    1280 *  720, 16: 9.0 (1.778 -0.176), 8 8 8, 60Hz
    1280 *  768, 16: 9.6 (1.667 -0.065), 8 8 8, 59Hz
    1280 *  768, 16: 9.6 (1.667 -0.065), 8 8 8, 60Hz
    1280 *  800, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1280 *  800, 16:10.0 (1.600 0.002), 8 8 8, 60Hz
    1280 *  960, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
    1280 *  960, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
    1280 * 1024, 16:12.8 (1.250 0.352), 8 8 8, 59Hz
    1280 * 1024, 16:12.8 (1.250 0.352), 8 8 8, 60Hz
    1360 *  768, 16: 9.0 (1.771 -0.169), 8 8 8, 59Hz
    1360 *  768, 16: 9.0 (1.771 -0.169), 8 8 8, 60Hz
    1366 *  768, 16: 9.0 (1.779 -0.177), 8 8 8, 59Hz
    1366 *  768, 16: 9.0 (1.779 -0.177), 8 8 8, 60Hz
    1400 * 1050, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
    1400 * 1050, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
    1440 *  900, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1440 *  900, 16:10.0 (1.600 0.002), 8 8 8, 60Hz
    1600 *  900, 16: 9.0 (1.778 -0.176), 8 8 8, 59Hz
    1600 *  900, 16: 9.0 (1.778 -0.176), 8 8 8, 60Hz
    1600 * 1200, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
    1600 * 1200, 16:12.0 (1.333 0.269), 8 8 8, 60Hz
    1680 * 1050, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1680 * 1050, 16:10.0 (1.600 0.002), 8 8 8, 60Hz
    1920 * 1080, 16: 9.0 (1.778 -0.176), 8 8 8, 59Hz
    1920 * 1080, 16: 9.0 (1.778 -0.176), 8 8 8, 60Hz
    1920 * 1200, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1920 * 1200, 16:10.0 (1.600 0.002), 8 8 8, 60Hz

Kept the best match for each width:    (physical monitor a-r is 1.602)
     320 *  200, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
     400 *  300, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
     512 *  384, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
     640 *  400, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
     720 *  480, 16:10.7 (1.500 0.102), 8 8 8, 59Hz
     800 *  600, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
    1024 *  768, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
    1152 *  864, 16:12.0 (1.333 0.269), 8 8 8, 59Hz
    1280 *  800, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1360 *  768, 16: 9.0 (1.771 -0.169), 8 8 8, 59Hz
    1440 *  900, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1600 *  900, 16: 9.0 (1.778 -0.176), 8 8 8, 59Hz
    1680 * 1050, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1920 * 1200, 16:10.0 (1.600 0.002), 8 8 8, 59Hz

Mismatching aspect ratios removed:    (physical monitor a-r is 1.602)
     320 *  200, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
     640 *  400, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1280 *  800, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1440 *  900, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1680 * 1050, 16:10.0 (1.600 0.002), 8 8 8, 59Hz
    1920 * 1200, 16:10.0 (1.600 0.002), 8 8 8, 59Hz

:slight_smile:

That does look like a nicely reduced list. I’d consider adding an option to list all modes, but otherwise this does seem pretty perfect.

Just curious if it’s always a good idea to ignore refresh rate? I don’t know if this is how it works with high-refresh rate monitors, but I can imagine there being display modes at the same resolution but different rates. e.g. 1920x1080@60Hz, 120Hz, or 144Hz. If those options are collapsed in your list, a) which one do you choose? b) is there another way for the user to force a specific rate outside of your program? They might not want to operate at the highest available refresh rate, for some reason. I’d be interested to know the answer to this.

Hi @tombsar,

I have no proper answer to this: at this time, I just use the defaults for bit depth and refresh rate. An alternative would be to always pick the maximum refresh rate unless there is a good reason not to (I’m not aware of any).

Of course, the above is not complete: application requirements such as minimum bit depths for RGB, depth, stencil etc. may well be used to affect the list result. Maybe I’ll later add an option for the user to apply manual overrides, e.g. via a config file, so that if the automatism fails, there is a least a way to recover.