Made ContextHandle a struct to reduce GC pressure (ContextHandles are created per frame).

Added xml documentation for the ContextHandle.
Made the casts between ContextHandles and IntPtrs explicit.
Updated all ContextHandle consumers to reflect the explicit cast.
This commit is contained in:
the_fiddler 2008-11-23 20:17:50 +00:00
parent c90c143ec3
commit 62da31df48
7 changed files with 183 additions and 73 deletions

View file

@ -24,7 +24,8 @@ namespace OpenTK.Audio
bool disposed;
bool is_processing;
ContextHandle device_handle, context_handle;
IntPtr device_handle;
ContextHandle context_handle;
bool context_exists;
string device_name;
@ -298,7 +299,7 @@ namespace OpenTK.Audio
context_handle = Alc.CreateContext(device_handle, attributes.ToArray());
if (context_handle == IntPtr.Zero)
if (context_handle == ContextHandle.Zero)
{
Alc.CloseDevice(device_handle);
throw new AudioContextException("The audio context could not be created with the specified parameters.");
@ -351,7 +352,7 @@ namespace OpenTK.Audio
{
lock (audio_context_lock)
{
if (!Alc.MakeContextCurrent(context != null ? (IntPtr)context.context_handle : IntPtr.Zero))
if (!Alc.MakeContextCurrent(context != null ? context.context_handle : ContextHandle.Zero))
throw new AudioContextException(String.Format("ALC {0} error detected at {1}.",
Alc.GetError(context != null ? (IntPtr)context.context_handle : IntPtr.Zero).ToString(),
context != null ? context.ToString() : "null"));
@ -395,7 +396,7 @@ namespace OpenTK.Audio
#region IntPtr Device
IntPtr Device { get { return device_handle.Handle; } }
IntPtr Device { get { return device_handle; } }
#endregion
@ -583,7 +584,7 @@ namespace OpenTK.Audio
if (this.IsCurrent)
this.IsCurrent = false;
if (context_handle != IntPtr.Zero)
if (context_handle != ContextHandle.Zero)
{
available_contexts.Remove(context_handle);
Alc.DestroyContext(context_handle);

View file

@ -89,7 +89,7 @@ namespace OpenTK.Audio
/// <returns>Returns a pointer to the new context (NULL on failure). The attribute list can be NULL, or a zero terminated list of integer pairs composed of valid ALC attribute tokens and requested values.</returns>
[DllImport(Alc.Lib, EntryPoint = "alcCreateContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity]
[CLSCompliant(false)]
unsafe public static extern IntPtr CreateContext([In] IntPtr device, [In] int* attrlist);
unsafe public static extern ContextHandle CreateContext([In] IntPtr device, [In] int* attrlist);
// ALC_API ALCcontext * ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist );
/// <summary>This function creates a context using a specified device.</summary>
@ -97,7 +97,7 @@ namespace OpenTK.Audio
/// <param name="attrlist">an array of a set of attributes: ALC_FREQUENCY, ALC_MONO_SOURCES, ALC_REFRESH, ALC_STEREO_SOURCES, ALC_SYNC</param>
/// <returns>Returns a pointer to the new context (NULL on failure).</returns>
/// <remarks>The attribute list can be NULL, or a zero terminated list of integer pairs composed of valid ALC attribute tokens and requested values.</remarks>
public static IntPtr CreateContext(IntPtr device, int[] attriblist)
public static ContextHandle CreateContext(IntPtr device, int[] attriblist)
{
unsafe
{
@ -114,38 +114,38 @@ namespace OpenTK.Audio
/// <param name="context">A pointer to the new context.</param>
/// <returns>Returns True on success, or False on failure.</returns>
[DllImport(Alc.Lib, EntryPoint = "alcMakeContextCurrent", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
public static extern bool MakeContextCurrent([In] IntPtr context);
public static extern bool MakeContextCurrent([In] ContextHandle context);
// ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context );
/// <summary>This function tells a context to begin processing. When a context is suspended, changes in OpenAL state will be accepted but will not be processed. alcSuspendContext can be used to suspend a context, and then all the OpenAL state changes can be applied at once, followed by a call to alcProcessContext to apply all the state changes immediately. In some cases, this procedure may be more efficient than application of properties in a non-suspended state. In some implementations, process and suspend calls are each a NOP.</summary>
/// <param name="context">a pointer to the new context</param>
[DllImport(Alc.Lib, EntryPoint = "alcProcessContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
public static extern void ProcessContext([In] IntPtr context);
public static extern void ProcessContext([In] ContextHandle context);
// ALC_API void ALC_APIENTRY alcProcessContext( ALCcontext *context );
/// <summary>This function suspends processing on a specified context. When a context is suspended, changes in OpenAL state will be accepted but will not be processed. A typical use of alcSuspendContext would be to suspend a context, apply all the OpenAL state changes at once, and then call alcProcessContext to apply all the state changes at once. In some cases, this procedure may be more efficient than application of properties in a non-suspended state. In some implementations, process and suspend calls are each a NOP.</summary>
/// <param name="context">a pointer to the context to be suspended.</param>
[DllImport(Alc.Lib, EntryPoint = "alcSuspendContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
public static extern void SuspendContext([In] IntPtr context);
public static extern void SuspendContext([In] ContextHandle context);
// ALC_API void ALC_APIENTRY alcSuspendContext( ALCcontext *context );
/// <summary>This function destroys a context.</summary>
/// <param name="context">a pointer to the new context.</param>
[DllImport(Alc.Lib, EntryPoint = "alcDestroyContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
public static extern void DestroyContext([In] IntPtr context);
public static extern void DestroyContext([In] ContextHandle context);
// ALC_API void ALC_APIENTRY alcDestroyContext( ALCcontext *context );
/// <summary>This function retrieves the current context.</summary>
/// <returns>Returns a pointer to the current context.</returns>
[DllImport(Alc.Lib, EntryPoint = "alcGetCurrentContext", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
public static extern IntPtr GetCurrentContext();
public static extern ContextHandle GetCurrentContext();
// ALC_API ALCcontext * ALC_APIENTRY alcGetCurrentContext( void );
/// <summary>This function retrieves a context's device pointer.</summary>
/// <param name="context">a pointer to a context.</param>
/// <returns>Returns a pointer to the specified context's device.</returns>
[DllImport(Alc.Lib, EntryPoint = "alcGetContextsDevice", ExactSpelling = true, CallingConvention = Alc.Style), SuppressUnmanagedCodeSecurity()]
public static extern IntPtr GetContextsDevice([In] IntPtr context);
public static extern IntPtr GetContextsDevice([In] ContextHandle context);
// ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice( ALCcontext *context );
#endregion Context Management

View file

@ -12,16 +12,147 @@ using System.Text;
namespace OpenTK
{
public class ContextHandle : /*System.Runtime.InteropServices.SafeHandle,*/ IComparable<ContextHandle>
/// <summary>
/// Represents a handle to an OpenGL or OpenAL context.
/// </summary>
public struct ContextHandle : IComparable<ContextHandle>, IEquatable<ContextHandle>
{
#region Fields
IntPtr handle;
/// <summary>
/// Gets a System.IntPtr that represents the handle of this ContextHandle.
/// </summary>
public IntPtr Handle { get { return handle; } }
public ContextHandle() /*: base(IntPtr.Zero, true)*/ { }
/// <summary>A read-only field that represents a handle that has been initialized to zero.</summary>
public static readonly ContextHandle Zero = new ContextHandle(IntPtr.Zero);
#endregion
#region Constructors
/// <summary>
/// Constructs a new instance with the specified handle.
/// </summary>
/// <param name="h">A System.IntPtr containing the value for this instance.</param>
public ContextHandle(IntPtr h) { handle = h; }
#endregion
#region Public Members
#region ToString
/// <summary>
/// Converts this instance to its equivalent string representation.
/// </summary>
/// <returns>A System.String that contains the string representation of this instance.</returns>
public override string ToString()
{
return Handle.ToString();
}
#endregion
#region Equals
/// <summary>
/// Compares this instance to the specified object.
/// </summary>
/// <param name="obj">The System.Object to compare to.</param>
/// <returns>True if obj is a ContextHandle that is equal to this instance; false otherwise.</returns>
public override bool Equals(object obj)
{
if (obj is ContextHandle)
return this.Equals((ContextHandle)obj);
return false;
}
#endregion
#region GetHashCode
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A System.Int32 with the hash code of this instance.</returns>
public override int GetHashCode()
{
return Handle.GetHashCode();
}
#endregion
#region public static explicit operator IntPtr(ContextHandle c)
/// <summary>
/// Converts the specified ContextHandle to the equivalent IntPtr.
/// </summary>
/// <param name="c">The ContextHandle to convert.</param>
/// <returns>A System.IntPtr equivalent to the specified ContextHandle.</returns>
public static explicit operator IntPtr(ContextHandle c)
{
return c != ContextHandle.Zero ? c.handle : IntPtr.Zero;
}
#endregion
#region public static explicit operator ContextHandle(IntPtr p)
/// <summary>
/// Converts the specified IntPtr to the equivalent ContextHandle.
/// </summary>
/// <param name="p">The System.IntPtr to convert.</param>
/// <returns>A ContextHandle equivalent to the specified IntPtr.</returns>
public static explicit operator ContextHandle(IntPtr p)
{
return new ContextHandle(p);
}
#endregion
#region public static bool operator ==(ContextHandle left, ContextHandle right)
/// <summary>
/// Compares two ContextHandles for equality.
/// </summary>
/// <param name="left">The ContextHandle to compare.</param>
/// <param name="right">The ContextHandle to compare to.</param>
/// <returns>True if left is equal to right; false otherwise.</returns>
public static bool operator ==(ContextHandle left, ContextHandle right)
{
return left.Equals(right);
}
#endregion
#region public static bool operator !=(ContextHandle left, ContextHandle right)
/// <summary>
/// Compares two ContextHandles for inequality.
/// </summary>
/// <param name="left">The ContextHandle to compare.</param>
/// <param name="right">The ContextHandle to compare to.</param>
/// <returns>True if left is not equal to right; false otherwise.</returns>
public static bool operator !=(ContextHandle left, ContextHandle right)
{
return !left.Equals(right);
}
#endregion
#endregion
#region IComparable<ContextHandle> Members
/// <summary>
/// Compares the numerical value of this instance to the specified ContextHandle and
/// returns a value indicating their relative order.
/// </summary>
/// <param name="other">The ContextHandle to compare to.</param>
/// <returns>Less than 0, if this instance is less than other; 0 if both are equal; Greater than 0 if other is greater than this instance.</returns>
public int CompareTo(ContextHandle other)
{
unsafe { return (int)((int*)other.handle.ToPointer() - (int*)this.handle.ToPointer()); }
@ -29,46 +160,18 @@ namespace OpenTK
#endregion
public override string ToString()
#region IEquatable<ContextHandle> Members
/// <summary>
/// Compares this instance to the specified ContextHandle for equality.
/// </summary>
/// <param name="other">The ContextHandle to compare to.</param>
/// <returns>True if this instance is equal to other; false otherwise.</returns>
public bool Equals(ContextHandle other)
{
return Handle.ToString();
return Handle == other.Handle;
}
public override bool Equals(object obj)
{
if (obj is ContextHandle)
return this.Handle == ((ContextHandle)obj).Handle;
return false;
}
public override int GetHashCode()
{
return Handle.GetHashCode();
}
/// <summary>A read-only field that represents a handle that has been initialized to zero.</summary>
public static readonly ContextHandle Zero = new ContextHandle(IntPtr.Zero);
/*
public override bool IsInvalid
{
get { return handle == IntPtr.Zero; }
}
protected override bool ReleaseHandle()
{
throw new NotImplementedException();
}
*/
public static implicit operator IntPtr(ContextHandle c)
{
return c != null ? c.handle : IntPtr.Zero;
}
public static implicit operator ContextHandle(IntPtr p)
{
return new ContextHandle(p);
}
#endregion
}
}

View file

@ -37,7 +37,7 @@ namespace OpenTK.Platform
public void CreateContext(bool direct, IGraphicsContext source)
{
if (handle == null)
if (handle == ContextHandle.Zero)
{
++handle_count;
handle = new ContextHandle((IntPtr)handle_count);

View file

@ -75,9 +75,9 @@ namespace OpenTK.Platform.Windows
// and Wgl extensions will fail to load.
Debug.Write("Creating render context... ");
renderContext = new ContextHandle(Wgl.Imports.CreateContext(currentWindow.DeviceContext));
if (renderContext == IntPtr.Zero)
if (renderContext == ContextHandle.Zero)
renderContext = new ContextHandle(Wgl.Imports.CreateContext(currentWindow.DeviceContext));
if (renderContext == IntPtr.Zero)
if (renderContext == ContextHandle.Zero)
throw new GraphicsContextException(String.Format("Context creation failed. Wgl.CreateContext() error: {0}.",
Marshal.GetLastWin32Error()));
@ -86,7 +86,7 @@ namespace OpenTK.Platform.Windows
if (sharedContext != null)
{
Debug.Print("Sharing state with context {0}", sharedContext.ToString());
Wgl.Imports.ShareLists((sharedContext as IGraphicsContextInternal).Context, renderContext);
Wgl.Imports.ShareLists((sharedContext as IGraphicsContextInternal).Context.Handle, renderContext.Handle);
}
}
@ -94,8 +94,8 @@ namespace OpenTK.Platform.Windows
{
if (window == null) throw new ArgumentNullException("window");
renderContext = Wgl.GetCurrentContext();
if (renderContext == IntPtr.Zero)
renderContext = new ContextHandle(Wgl.GetCurrentContext());
if (renderContext == ContextHandle.Zero)
throw new InvalidOperationException("No OpenGL context is current in the calling thread.");
currentWindow = (WinWindowInfo)window;
@ -156,7 +156,7 @@ namespace OpenTK.Platform.Windows
throw new ArgumentException("window", "Must point to a valid window.");
currentWindow = (WinWindowInfo)window;
success = Wgl.Imports.MakeCurrent(((WinWindowInfo)window).DeviceContext, this.renderContext);
success = Wgl.Imports.MakeCurrent(((WinWindowInfo)window).DeviceContext, this.renderContext.Handle);
}
else
success = Wgl.Imports.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
@ -173,7 +173,7 @@ namespace OpenTK.Platform.Windows
public bool IsCurrent
{
get { return Wgl.GetCurrentContext() == this.renderContext; }
get { return Wgl.GetCurrentContext() == this.renderContext.Handle; }
/*
set
{
@ -336,7 +336,7 @@ namespace OpenTK.Platform.Windows
static ContextHandle GetCurrentContext()
{
return Wgl.GetCurrentContext();
return new ContextHandle(Wgl.GetCurrentContext());
}
#endregion
@ -388,7 +388,7 @@ namespace OpenTK.Platform.Windows
if (Destroy != null)
Destroy(this, EventArgs.Empty);
if (renderContext != IntPtr.Zero)
if (renderContext != ContextHandle.Zero)
{
try
{
@ -396,7 +396,7 @@ namespace OpenTK.Platform.Windows
Debug.Print("Failed to make OpenGL context {0} non current. Error: {1}",
renderContext.ToString(), Marshal.GetLastWin32Error());
if (!Wgl.Imports.DeleteContext(renderContext))
if (!Wgl.Imports.DeleteContext(renderContext.Handle))
Debug.Print("Failed to destroy OpenGL context {0}. Error: {1}",
renderContext.ToString(), Marshal.GetLastWin32Error());
}
@ -408,7 +408,7 @@ namespace OpenTK.Platform.Windows
Debug.WriteLine(e.ToString());
Debug.Unindent();
}
renderContext = null;
renderContext = ContextHandle.Zero;
}
//if (deviceContext != IntPtr.Zero)

View file

@ -283,12 +283,18 @@ namespace OpenTK.Platform.X11
[DllImport(Library, EntryPoint = "glXDestroyContext")]
public static extern void DestroyContext(IntPtr dpy, IntPtr context);
[DllImport(Library, EntryPoint = "glXDestroyContext")]
public static extern void DestroyContext(IntPtr dpy, ContextHandle context);
[DllImport(Library, EntryPoint = "glXGetCurrentContext")]
public static extern IntPtr GetCurrentContext();
[DllImport(Library, EntryPoint = "glXMakeCurrent")]
public static extern bool MakeCurrent(IntPtr display, IntPtr drawable, IntPtr context);
[DllImport(Library, EntryPoint = "glXMakeCurrent")]
public static extern bool MakeCurrent(IntPtr display, IntPtr drawable, ContextHandle context);
[DllImport(Library, EntryPoint = "glXSwapBuffers")]
public static extern void SwapBuffers(IntPtr display, IntPtr drawable);

View file

@ -21,7 +21,7 @@ namespace OpenTK.Platform.X11
/// </summary>
internal sealed class X11GLContext : IGraphicsContext, IGraphicsContextInternal
{
IntPtr context;
ContextHandle context;
//X11WindowInfo window;
X11WindowInfo currentWindow;
//IntPtr visual;
@ -108,10 +108,10 @@ namespace OpenTK.Platform.X11
lock (API.Lock)
{
XVisualInfo info = window.VisualInfo; // Cannot pass a Property by reference.
context = Glx.CreateContext(window.Display, ref info, shareHandle.Handle, direct);
context = new ContextHandle(Glx.CreateContext(window.Display, ref info, shareHandle.Handle, direct));
// Context creation succeeded, return.
if (context != IntPtr.Zero)
if (context != ContextHandle.Zero)
{
Debug.Print("done! (id: {0})", context);
return;
@ -120,8 +120,8 @@ namespace OpenTK.Platform.X11
// Context creation failed. Retry with a non-shared context with the direct/indirect bit flipped.
Debug.Print("failed.");
Debug.Write(String.Format("Creating OpenGL context: {0}, not shared... ", !direct ? "direct" : "indirect"));
context = Glx.CreateContext(window.Display, ref info, IntPtr.Zero, !direct);
if (context != IntPtr.Zero)
context = new ContextHandle(Glx.CreateContext(window.Display, ref info, IntPtr.Zero, !direct));
if (context != ContextHandle.Zero)
{
Debug.Print("done! (id: {0})", context);
return;
@ -173,7 +173,7 @@ namespace OpenTK.Platform.X11
Debug.Write(String.Format("Making context {0} current on thread {1} (Display: {2}, Screen: {3}, Window: {4})... ",
context, System.Threading.Thread.CurrentThread.ManagedThreadId, w.Display, w.Screen, w.WindowHandle));
if (w.Display == IntPtr.Zero || w.WindowHandle == IntPtr.Zero || context == IntPtr.Zero)
if (w.Display == IntPtr.Zero || w.WindowHandle == IntPtr.Zero || context == ContextHandle.Zero)
throw new InvalidOperationException("Invalid display, window or context.");
result = Glx.MakeCurrent(w.Display, w.WindowHandle, context);
@ -190,7 +190,7 @@ namespace OpenTK.Platform.X11
public bool IsCurrent
{
get { return Glx.GetCurrentContext() == this.context; }
get { return Glx.GetCurrentContext() == this.context.Handle; }
//set
//{
// if (value)
@ -271,7 +271,7 @@ namespace OpenTK.Platform.X11
#endregion
#region IntPtr IGLContextInternal.Context
#region ContextHandle IGLContextInternal.Context
ContextHandle IGraphicsContextInternal.Context
{