Merge branch 'graphicsmode' into develop

This commit is contained in:
Stefanos A 2014-01-22 23:32:51 +01:00
commit 40ce2c4288
7 changed files with 321 additions and 191 deletions

View file

@ -22,7 +22,6 @@ namespace OpenTK.Graphics
IntPtr? index = null; // The id of the pixel format or visual. IntPtr? index = null; // The id of the pixel format or visual.
static GraphicsMode defaultMode; static GraphicsMode defaultMode;
static IGraphicsMode implementation;
static readonly object SyncRoot = new object(); static readonly object SyncRoot = new object();
#region Constructors #region Constructors
@ -44,7 +43,7 @@ namespace OpenTK.Graphics
{ {
if (depth < 0) throw new ArgumentOutOfRangeException("depth", "Must be greater than, or equal to zero."); if (depth < 0) throw new ArgumentOutOfRangeException("depth", "Must be greater than, or equal to zero.");
if (stencil < 0) throw new ArgumentOutOfRangeException("stencil", "Must be greater than, or equal to zero."); if (stencil < 0) throw new ArgumentOutOfRangeException("stencil", "Must be greater than, or equal to zero.");
if (buffers <= 0) throw new ArgumentOutOfRangeException("buffers", "Must be greater than zero."); if (buffers < 0) throw new ArgumentOutOfRangeException("buffers", "Must be greater than, or equal to zero.");
if (samples < 0) throw new ArgumentOutOfRangeException("samples", "Must be greater than, or equal to zero."); if (samples < 0) throw new ArgumentOutOfRangeException("samples", "Must be greater than, or equal to zero.");
this.Index = index; this.Index = index;
@ -255,7 +254,14 @@ namespace OpenTK.Graphics
{ {
return samples; return samples;
} }
private set { samples = value; } private set
{
// Clamp antialiasing samples to max 64x
// This protects against a potential DOS during
// mode selection, when the user requests an
// abnormally high AA level.
samples = MathHelper.Clamp(value, 0, 64);
}
} }
#endregion #endregion

View file

@ -52,8 +52,6 @@ namespace OpenTK.Platform.MacOS
DisplayDevice device; DisplayDevice device;
bool mIsFullscreen = false; bool mIsFullscreen = false;
readonly MacOSGraphicsMode ModeSelector = new MacOSGraphicsMode();
public AglContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext) public AglContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext)
{ {
Debug.Print("Context Type: {0}", shareContext); Debug.Print("Context Type: {0}", shareContext);
@ -103,6 +101,7 @@ namespace OpenTK.Platform.MacOS
aglAttributes.Add((int)pixelFormatAttribute); aglAttributes.Add((int)pixelFormatAttribute);
aglAttributes.Add(value); aglAttributes.Add(value);
} }
void CreateContext(GraphicsMode mode, CarbonWindowInfo carbonWindow, IntPtr shareContextRef, bool fullscreen) void CreateContext(GraphicsMode mode, CarbonWindowInfo carbonWindow, IntPtr shareContextRef, bool fullscreen)
{ {
Debug.Print("AGL pixel format attributes:"); Debug.Print("AGL pixel format attributes:");
@ -110,8 +109,6 @@ namespace OpenTK.Platform.MacOS
AGLPixelFormat myAGLPixelFormat; AGLPixelFormat myAGLPixelFormat;
// Choose a pixel format with the attributes we specified. // Choose a pixel format with the attributes we specified.
if (fullscreen)
{
IntPtr gdevice; IntPtr gdevice;
IntPtr cgdevice = GetQuartzDevice(carbonWindow); IntPtr cgdevice = GetQuartzDevice(carbonWindow);
@ -123,38 +120,19 @@ namespace OpenTK.Platform.MacOS
if (status != OSStatus.NoError) if (status != OSStatus.NoError)
throw new MacOSException(status, "DMGetGDeviceByDisplayID failed."); throw new MacOSException(status, "DMGetGDeviceByDisplayID failed.");
myAGLPixelFormat = ModeSelector.SelectPixelFormat( IGraphicsMode selector = new MacOSGraphicsMode(gdevice);
Mode = selector.SelectGraphicsMode(
mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples, mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples,
mode.AccumulatorFormat, mode.Buffers, mode.Stereo, mode.AccumulatorFormat, mode.Buffers, mode.Stereo);
true, gdevice);
Agl.AglError err = Agl.GetError();
if (myAGLPixelFormat == IntPtr.Zero || err == Agl.AglError.BadPixelFormat)
{
Debug.Print("Failed to create full screen pixel format.");
Debug.Print("Trying again to create a non-fullscreen pixel format.");
CreateContext(mode, carbonWindow, shareContextRef, false);
return;
}
}
else
{
myAGLPixelFormat = ModeSelector.SelectPixelFormat(
mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples,
mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
false, IntPtr.Zero);
MyAGLReportError("aglChoosePixelFormat"); MyAGLReportError("aglChoosePixelFormat");
}
Debug.Print("Creating AGL context. Sharing with {0}", shareContextRef); Debug.Print("Creating AGL context. Sharing with {0}", shareContextRef);
myAGLPixelFormat = Mode.Index.Value;
// create the context and share it with the share reference. // create the context and share it with the share reference.
Handle = new ContextHandle(Agl.aglCreateContext(myAGLPixelFormat, shareContextRef)); Handle = new ContextHandle(Agl.aglCreateContext(myAGLPixelFormat, shareContextRef));
MyAGLReportError("aglCreateContext"); MyAGLReportError("aglCreateContext");
Mode = ModeSelector.GetGraphicsModeFromPixelFormat(myAGLPixelFormat);
// Free the pixel format from memory. // Free the pixel format from memory.
Agl.aglDestroyPixelFormat(myAGLPixelFormat); Agl.aglDestroyPixelFormat(myAGLPixelFormat);
MyAGLReportError("aglDestroyPixelFormat"); MyAGLReportError("aglDestroyPixelFormat");

View file

@ -37,14 +37,47 @@ namespace OpenTK.Platform.MacOS
class MacOSGraphicsMode : IGraphicsMode class MacOSGraphicsMode : IGraphicsMode
{ {
readonly IntPtr Device;
public MacOSGraphicsMode(IntPtr device)
{
Device = device;
}
#region IGraphicsMode Members #region IGraphicsMode Members
public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil,
int samples, ColorFormat accum, int buffers, bool stereo) int samples, ColorFormat accum, int buffers, bool stereo)
{ {
IntPtr pixelformat = SelectPixelFormat( IntPtr pixelformat;
do
{
pixelformat = SelectPixelFormat(
color, depth, stencil, samples, accum, buffers, stereo,
true, Device);
Agl.AglError err = Agl.GetError();
if (pixelformat == IntPtr.Zero || err == Agl.AglError.BadPixelFormat)
{
Debug.Print("Failed to create full screen pixel format.");
Debug.Print("Trying again to create a non-fullscreen pixel format.");
pixelformat = SelectPixelFormat(
color, depth, stencil, samples, accum, buffers, stereo, color, depth, stencil, samples, accum, buffers, stereo,
false, IntPtr.Zero); false, IntPtr.Zero);
}
if (pixelformat == IntPtr.Zero)
{
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 (pixelformat == IntPtr.Zero);
return GetGraphicsModeFromPixelFormat(pixelformat); return GetGraphicsModeFromPixelFormat(pixelformat);
} }
@ -52,7 +85,7 @@ namespace OpenTK.Platform.MacOS
#region Internal Members #region Internal Members
internal GraphicsMode GetGraphicsModeFromPixelFormat(IntPtr pixelformat) GraphicsMode GetGraphicsModeFromPixelFormat(IntPtr pixelformat)
{ {
int r, g, b, a; int r, g, b, a;
Agl.aglDescribePixelFormat(pixelformat, Agl.PixelFormatAttribute.AGL_RED_SIZE, out r); Agl.aglDescribePixelFormat(pixelformat, Agl.PixelFormatAttribute.AGL_RED_SIZE, out r);
@ -75,7 +108,7 @@ namespace OpenTK.Platform.MacOS
depth, stencil, samples, new ColorFormat(ar, ag, ab, aa), buffers + 1, stereo != 0); depth, stencil, samples, new ColorFormat(ar, ag, ab, aa), buffers + 1, stereo != 0);
} }
internal IntPtr SelectPixelFormat(ColorFormat color, int depth, int stencil, int samples, IntPtr SelectPixelFormat(ColorFormat color, int depth, int stencil, int samples,
ColorFormat accum, int buffers, bool stereo, bool fullscreen, IntPtr device) ColorFormat accum, int buffers, bool stereo, bool fullscreen, IntPtr device)
{ {
List<int> attribs = new List<int>(); List<int> attribs = new List<int>();

View file

@ -62,9 +62,21 @@ namespace OpenTK.Platform.SDL2
: this(win) : this(win)
{ {
lock (SDL.Sync) lock (SDL.Sync)
{
bool retry = false;
do
{ {
SetGLAttributes(mode, shareContext, major, minor, flags); SetGLAttributes(mode, shareContext, major, minor, flags);
SdlContext = new ContextHandle(SDL.GL.CreateContext(Window.Handle)); SdlContext = new ContextHandle(SDL.GL.CreateContext(Window.Handle));
// If we failed to create a valid context, relax the GraphicsMode
// and try again.
retry =
SdlContext == ContextHandle.Zero &&
Utilities.RelaxGraphicsMode(ref mode);
}
while (retry);
if (SdlContext == ContextHandle.Zero) if (SdlContext == ContextHandle.Zero)
{ {
var error = SDL.GetError(); var error = SDL.GetError();
@ -152,12 +164,37 @@ namespace OpenTK.Platform.SDL2
stereo != 0 ? true : false); stereo != 0 ? true : false);
} }
static void ClearGLAttributes()
{
SDL.GL.SetAttribute(ContextAttribute.ACCUM_ALPHA_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.ACCUM_RED_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.ACCUM_GREEN_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.ACCUM_BLUE_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.DOUBLEBUFFER, 0);
SDL.GL.SetAttribute(ContextAttribute.ALPHA_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.RED_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.GREEN_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.BLUE_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.DEPTH_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.MULTISAMPLEBUFFERS, 0);
SDL.GL.SetAttribute(ContextAttribute.MULTISAMPLESAMPLES, 0);
SDL.GL.SetAttribute(ContextAttribute.STENCIL_SIZE, 0);
SDL.GL.SetAttribute(ContextAttribute.STEREO, 0);
SDL.GL.SetAttribute(ContextAttribute.CONTEXT_MAJOR_VERSION, 1);
SDL.GL.SetAttribute(ContextAttribute.CONTEXT_MINOR_VERSION, 0);
SDL.GL.SetAttribute(ContextAttribute.CONTEXT_FLAGS, 0);
SDL.GL.SetAttribute(ContextAttribute.CONTEXT_EGL, 0);
SDL.GL.SetAttribute(ContextAttribute.CONTEXT_PROFILE_MASK, 0);
SDL.GL.SetAttribute(ContextAttribute.SHARE_WITH_CURRENT_CONTEXT, 0);
}
static void SetGLAttributes(GraphicsMode mode, static void SetGLAttributes(GraphicsMode mode,
IGraphicsContext shareContext, IGraphicsContext shareContext,
int major, int minor, int major, int minor,
GraphicsContextFlags flags) GraphicsContextFlags flags)
{ {
ContextProfileFlags cpflags = 0; ContextProfileFlags cpflags = 0;
ClearGLAttributes();
if (mode.AccumulatorFormat.BitsPerPixel > 0) if (mode.AccumulatorFormat.BitsPerPixel > 0)
{ {

View file

@ -307,5 +307,113 @@ namespace OpenTK.Platform
#endregion #endregion
#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
/// <summary>
/// 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
/// </summary>
/// <returns><c>true</c>, if a graphics mode parameter was relaxed, <c>false</c> otherwise.</returns>
/// <param name="color">Color bits.</param>
/// <param name="depth">Depth bits.</param>
/// <param name="stencil">Stencil bits.</param>
/// <param name="samples">Number of antialiasing samples.</param>
/// <param name="accum">Accumulator buffer bits.</param>
/// <param name="buffers">Number of rendering buffers (1 for single buffering, 2+ for double buffering, 0 for don't care).</param>
/// <param name="stereo">Stereoscopic rendering enabled/disabled.</param>
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 - 1, 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
} }
} }

View file

@ -96,16 +96,23 @@ namespace OpenTK.Platform.Windows
// hardware acceleration (e.g. we are running in a VM or in a remote desktop // hardware acceleration (e.g. we are running in a VM or in a remote desktop
// connection), this method will return 0 formats and we will fall back to // connection), this method will return 0 formats and we will fall back to
// ChoosePixelFormatPFD. // ChoosePixelFormatPFD.
GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode mode) GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode desired_mode)
{ {
GraphicsMode created_mode = null; GraphicsMode created_mode = null;
GraphicsMode mode = new GraphicsMode(desired_mode);
if (Wgl.SupportsExtension("WGL_ARB_pixel_format") && if (Wgl.SupportsExtension("WGL_ARB_pixel_format") &&
Wgl.SupportsFunction("wglChoosePixelFormatARB")) Wgl.SupportsFunction("wglChoosePixelFormatARB"))
{ {
int[] format = new int[1];
int count;
List<int> attributes = new List<int>(); List<int> attributes = new List<int>();
bool retry = false;
do
{
attributes.Clear();
attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb); attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb);
attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb); attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb);
attributes.Add((int)WGL_ARB_pixel_format.DrawToWindowArb); attributes.Add((int)WGL_ARB_pixel_format.DrawToWindowArb);
attributes.Add(1); attributes.Add(1);
@ -193,18 +200,20 @@ namespace OpenTK.Platform.Windows
attributes.Add(0); attributes.Add(0);
attributes.Add(0); attributes.Add(0);
int[] format = new int[1];
int count;
if (Wgl.Arb.ChoosePixelFormat(device, attributes.ToArray(), null, format.Length, format, out count) if (Wgl.Arb.ChoosePixelFormat(device, attributes.ToArray(), null, format.Length, format, out count)
&& count > 0) && count > 0)
{ {
created_mode = DescribePixelFormatARB(device, format[0]); created_mode = DescribePixelFormatARB(device, format[0]);
retry = false;
} }
else else
{ {
Debug.Print("[WGL] ChoosePixelFormatARB failed with {0}", Marshal.GetLastWin32Error()); Debug.Print("[WGL] ChoosePixelFormatARB failed with {0}", Marshal.GetLastWin32Error());
retry = Utilities.RelaxGraphicsMode(ref mode);
} }
} }
while (retry);
}
else else
{ {
Debug.WriteLine("[WGL] ChoosePixelFormatARB not supported on this context"); Debug.WriteLine("[WGL] ChoosePixelFormatARB not supported on this context");

View file

@ -52,48 +52,7 @@ namespace OpenTK.Platform.X11
if (visual == IntPtr.Zero) if (visual == IntPtr.Zero)
{ {
// Relax parameters and retry // Relax parameters and retry
if (stereo) if (!Utilities.RelaxGraphicsMode(ref color, ref depth, ref stencil, ref samples, ref accum, ref buffers, ref 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."); throw new GraphicsModeException("Requested GraphicsMode not available.");
} }
} }