Skip to content

Commit

Permalink
Merge branch 'graphicsmode' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
thefiddler committed Jan 22, 2014
2 parents 770b697 + 06a3d7e commit 40ce2c4
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 189 deletions.
12 changes: 9 additions & 3 deletions Source/OpenTK/Graphics/GraphicsMode.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public class GraphicsMode : IEquatable<GraphicsMode>
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
Expand All @@ -44,7 +43,7 @@ internal GraphicsMode(IntPtr? index, ColorFormat color, int depth, int stencil,
{ {
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;
Expand Down Expand Up @@ -255,7 +254,14 @@ public int Samples
{ {
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
Expand Down
56 changes: 17 additions & 39 deletions Source/OpenTK/Platform/MacOS/AglContext.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ class AglContext : DesktopGraphicsContext
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);
Expand Down Expand Up @@ -103,58 +101,38 @@ private void AddPixelAttrib(List<int> aglAttributes, Agl.PixelFormatAttribute pi
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:");


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 cgdevice = GetQuartzDevice(carbonWindow);
IntPtr gdevice;
IntPtr cgdevice = GetQuartzDevice(carbonWindow);

if (cgdevice == IntPtr.Zero)
cgdevice = (IntPtr)DisplayDevice.Default.Id;


OSStatus status = Carbon.API.DMGetGDeviceByDisplayID(cgdevice, out gdevice, false); if (cgdevice == IntPtr.Zero)
cgdevice = (IntPtr)DisplayDevice.Default.Id;


if (status != OSStatus.NoError) OSStatus status = Carbon.API.DMGetGDeviceByDisplayID(cgdevice, out gdevice, false);
throw new MacOSException(status, "DMGetGDeviceByDisplayID failed.");


myAGLPixelFormat = ModeSelector.SelectPixelFormat( if (status != OSStatus.NoError)
mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples, throw new MacOSException(status, "DMGetGDeviceByDisplayID failed.");
mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
true, gdevice); IGraphicsMode selector = new MacOSGraphicsMode(gdevice);

Mode = selector.SelectGraphicsMode(
Agl.AglError err = Agl.GetError(); mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples,
if (myAGLPixelFormat == IntPtr.Zero || err == Agl.AglError.BadPixelFormat) mode.AccumulatorFormat, mode.Buffers, mode.Stereo);
{ MyAGLReportError("aglChoosePixelFormat");
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");
}

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");
Expand Down
43 changes: 38 additions & 5 deletions Source/OpenTK/Platform/MacOS/MacOSGraphicsMode.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -37,22 +37,55 @@ 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;
color, depth, stencil, samples, accum, buffers, stereo, do
false, IntPtr.Zero); {
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,
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);
} }


#endregion #endregion


#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);
Expand All @@ -75,7 +108,7 @@ internal GraphicsMode GetGraphicsModeFromPixelFormat(IntPtr pixelformat)
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>();
Expand Down
41 changes: 39 additions & 2 deletions Source/OpenTK/Platform/SDL2/Sdl2GraphicsContext.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -63,8 +63,20 @@ public Sdl2GraphicsContext(GraphicsMode mode,
{ {
lock (SDL.Sync) lock (SDL.Sync)
{ {
SetGLAttributes(mode, shareContext, major, minor, flags); bool retry = false;
SdlContext = new ContextHandle(SDL.GL.CreateContext(Window.Handle)); do
{
SetGLAttributes(mode, shareContext, major, minor, flags);
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();
Expand Down Expand Up @@ -152,12 +164,37 @@ static GraphicsMode GetGLAttributes(ContextHandle sdlContext, out GraphicsContex
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)
{ {
Expand Down
108 changes: 108 additions & 0 deletions Source/OpenTK/Platform/Utilities.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -307,5 +307,113 @@ public static IWindowInfo CreateSdl2WindowInfo(IntPtr windowHandle)
#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
} }
} }
Loading

0 comments on commit 40ce2c4

Please sign in to comment.