diff --git a/Source/OpenTK/Platform/Utilities.cs b/Source/OpenTK/Platform/Utilities.cs index cbf0e811..27a2d269 100644 --- a/Source/OpenTK/Platform/Utilities.cs +++ b/Source/OpenTK/Platform/Utilities.cs @@ -307,5 +307,113 @@ namespace OpenTK.Platform #endregion #endregion + + #region RelaxGraphicsMode + + internal static bool RelaxGraphicsMode(ref GraphicsMode mode) + { + ColorFormat color = mode.ColorFormat; + int depth = mode.Depth; + int stencil = mode.Stencil; + int samples = mode.Samples; + ColorFormat accum = mode.AccumulatorFormat; + int buffers = mode.Buffers; + bool stereo = mode.Stereo; + + bool success = RelaxGraphicsMode( + ref color, ref depth, ref stencil, ref samples, + ref accum, ref buffers, ref stereo); + + mode = new GraphicsMode( + color, depth, stencil, samples, + accum, buffers, stereo); + + return success; + } + + /// \internal + /// + /// Relaxes graphics mode parameters. Use this function to increase compatibility + /// on systems that do not directly support a requested GraphicsMode. For example: + /// - user requested stereoscopic rendering, but GPU does not support stereo + /// - user requseted 16x antialiasing, but GPU only supports 4x + /// + /// true, if a graphics mode parameter was relaxed, false otherwise. + /// Color bits. + /// Depth bits. + /// Stencil bits. + /// Number of antialiasing samples. + /// Accumulator buffer bits. + /// Number of rendering buffers (1 for single buffering, 2+ for double buffering, 0 for don't care). + /// Stereoscopic rendering enabled/disabled. + internal static bool RelaxGraphicsMode(ref ColorFormat color, ref int depth, ref int stencil, ref int samples, ref ColorFormat accum, ref int buffers, ref bool stereo) + { + // Parameters are relaxed in order of importance. + // - Accumulator buffers are way outdated as a concept, + // so they go first. + // - Triple+ buffering is generally not supported by the + // core WGL/GLX/AGL/CGL/EGL specs, so we clamp + // to double-buffering as a second step. (If this doesn't help + // we will also fall back to undefined single/double buffering + // as a last resort). + // - AA samples are an easy way to increase compatibility + // so they go next. + // - Stereoscopic is only supported on very few GPUs + // (Quadro/FirePro series) so it goes next. + // - The rest of the parameters then follow. + + if (accum != 0) + { + accum = 0; + return true; + } + + if (buffers > 2) + { + buffers = 2; + return true; + } + + if (samples > 0) + { + samples = Math.Max(samples - 2, 0); + return true; + } + + if (stereo) + { + stereo = false; + return true; + } + + if (stencil != 0) + { + stencil = 0; + return true; + } + + if (depth != 0) + { + depth = 0; + return true; + } + + if (color != 24) + { + color = 24; + return true; + } + + if (buffers != 0) + { + buffers = 0; + return true; + } + + // no parameters left to relax, fail + return false; + } + + #endregion } } diff --git a/Source/OpenTK/Platform/X11/X11GraphicsMode.cs b/Source/OpenTK/Platform/X11/X11GraphicsMode.cs index 1c019036..000f45ee 100644 --- a/Source/OpenTK/Platform/X11/X11GraphicsMode.cs +++ b/Source/OpenTK/Platform/X11/X11GraphicsMode.cs @@ -52,49 +52,8 @@ namespace OpenTK.Platform.X11 if (visual == IntPtr.Zero) { // Relax parameters and retry - if (stereo) - { - stereo = false; - continue; - } - - if (accum != 0) - { - accum = 0; - continue; - } - - if (samples > 0) - { - samples = Math.Max(samples - 2, 0); - continue; - } - - if (stencil != 0) - { - stencil = 0; - continue; - } - - if (depth != 0) - { - depth = 0; - continue; - } - - if (color != 24) - { - color = 24; - continue; - } - - if (buffers != 0) - { - buffers = 0; - continue; - } - - throw new GraphicsModeException("Requested GraphicsMode not available."); + if (!Utilities.RelaxGraphicsMode(ref color, ref depth, ref stencil, ref samples, ref accum, ref buffers, ref stereo)) + throw new GraphicsModeException("Requested GraphicsMode not available."); } } while (visual == IntPtr.Zero);