Added automatic error checking for all OpenGL function calls (debug mode only). Begin()-End() regions are handled correctly.

This commit is contained in:
the_fiddler 2009-03-25 17:55:37 +00:00
parent 3914aaa1e6
commit fc103aa8ec
6 changed files with 203 additions and 81 deletions

View file

@ -2,7 +2,7 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted.
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal

View file

@ -350,11 +350,7 @@ namespace Bind.Structures
{
// No special wrapper needed - just call this delegate:
Function f = new Function(this);
if (f.ReturnType.CurrentType.ToLower().Contains("void"))
f.Body.Add(String.Format("{0};", f.CallString()));
else
f.Body.Add(String.Format("return {0};", f.CallString()));
f.CreateBody(false);
wrappers.Add(f);
}

View file

@ -36,6 +36,11 @@ namespace Bind.Structures
static Regex endings = new Regex(@"((([df]|u?[isb])v?)|v)", RegexOptions.Compiled | RegexOptions.RightToLeft);
static Regex endingsNotToTrim = new Regex("(ib|[tdrey]s|[eE]n[vd]|bled|Flagv|Tess|Status|Pixels)", RegexOptions.Compiled | RegexOptions.RightToLeft);
// Add a trailing v to functions matching this regex. Used to differntiate between overloads taking both
// a 'type' and a 'ref type' (such overloads are not CLS Compliant).
// The default Regex matches no functions. Create a new Regex in Bind.Generator classes to override the default behavior.
internal static Regex endingsAddV = new Regex("^0", RegexOptions.Compiled);
#endregion
#region Fields
@ -44,15 +49,6 @@ namespace Bind.Structures
int index;
#endregion
/// <summary>
/// Add a trailing v to functions matching this regex. Used to differntiate between overloads taking both
/// a 'type' and a 'ref type' (such overloads are not CLS Compliant).
/// </summary>
/// <remarks>
/// The default Regex matches no functions. Create a new Regex in Bind.Generator classes to override the default behavior.
/// </remarks>
internal static Regex endingsAddV = new Regex("^0", RegexOptions.Compiled);
#region --- Constructors ---
@ -72,12 +68,16 @@ namespace Bind.Structures
#endregion
#region public Delegate WrappedDelegate
public Delegate WrappedDelegate
{
get { return wrapped_delegate; }
set { wrapped_delegate = value; }
}
#endregion
#region public void TurnVoidPointersToIntPtr()
public void TurnVoidPointersToIntPtr()
@ -394,10 +394,10 @@ namespace Bind.Structures
#region public void CreateBody(bool wantCLSCompliance)
static List<string> handle_statements = new List<string>();
static List<string> handle_release_statements = new List<string>();
static List<string> fixed_statements = new List<string>();
static List<string> assign_statements = new List<string>();
readonly List<string> handle_statements = new List<string>();
readonly List<string> handle_release_statements = new List<string>();
readonly List<string> fixed_statements = new List<string>();
readonly List<string> assign_statements = new List<string>();
public void CreateBody(bool wantCLSCompliance)
{
@ -459,7 +459,21 @@ namespace Bind.Structures
}
}
if (!f.Unsafe || fixed_statements.Count > 0)
// Automatic OpenGL error checking.
// See OpenTK.Graphics.ErrorHelper for more information.
// Make sure that no error checking is added to the GetError function,
// as that would cause infinite recursion!
if (f.TrimmedName != "GetError")
{
f.Body.Add("#if DEBUG");
f.Body.Add("using (new ErrorHelper(GraphicsContext.CurrentContext))");
f.Body.Add("{");
if (f.TrimmedName == "Begin")
f.Body.Add("GraphicsContext.CurrentContext.EnterBeginRegion();");
f.Body.Add("#endif");
}
if (!f.Unsafe && fixed_statements.Count > 0)
{
f.Body.Add("unsafe");
f.Body.Add("{");
@ -529,7 +543,7 @@ namespace Bind.Structures
f.Body.Add("}");
}
if (!f.Unsafe || fixed_statements.Count > 0)
if (!f.Unsafe && fixed_statements.Count > 0)
{
f.Body.Unindent();
f.Body.Add("}");
@ -541,6 +555,15 @@ namespace Bind.Structures
f.Body.Add("}");
}
if (f.TrimmedName != "GetError")
{
f.Body.Add("#if DEBUG");
if (f.TrimmedName == "End")
f.Body.Add("GraphicsContext.CurrentContext.ExitBeginRegion();");
f.Body.Add("}");
f.Body.Add("#endif");
}
this.Body = f.Body;
}

View file

@ -0,0 +1,74 @@
#region License
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#endregion
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK.Graphics
{
// Used in debug-mode only, for automatic OpenGL error-checking.
//
// Works like this: an instance is created before each OpenGL function is called.
// The constructor resets the OpenGL error state. Once the native function returns,
// the error state is checked again, raising the relevant exceptions.
//
// A using-region is used to ensure Dispose() is called.
//
// Make sure that no error checking is added to the GetError function,
// as that would cause infinite recursion!
struct ErrorHelper : IDisposable
{
#region Fields
readonly GraphicsContext Context;
#endregion
#region Constructors
public ErrorHelper(GraphicsContext context)
{
if (context == null)
throw new GraphicsContextMissingException();
Context = context;
Context.ResetErrors();
}
#endregion
#region IDisposable Members
public void Dispose()
{
Context.CheckErrors();
}
#endregion
}
}

View file

@ -266,7 +266,6 @@ namespace OpenTK.Graphics
MethodInfo m;
return
GetExtensionDelegate(name, signature) ??
/*((m = importsClass.GetMethod(name.Substring(2), BindingFlags.Static | BindingFlags.NonPublic)) != null ?*/
(Imports.FunctionMap.TryGetValue((name.Substring(2)), out m) ?
Delegate.CreateDelegate(signature, m) : null);
}

View file

@ -120,6 +120,8 @@ namespace OpenTK.Graphics
#region --- Static Members ---
#region public static GraphicsContext CreateDummyContext()
/// <summary>
/// Creates a dummy GraphicsContext to allow OpenTK to work with contexts created by external libraries.
/// </summary>
@ -143,34 +145,27 @@ namespace OpenTK.Graphics
#endregion
#region --- Private Members ---
#region void ContextDestroyed(IGraphicsContext context, EventArgs e)
#region public static void Assert()
/// <summary>
/// Handles the Destroy event.
/// Checks if a GraphicsContext exists in the calling thread and throws a GraphicsContextException if it doesn't.
/// </summary>
/// <param name="context">The OpenTK.Platform.IGraphicsContext that was destroyed.</param>
/// <param name="e">Not used.</param>
void ContextDestroyed(IGraphicsContext context, EventArgs e)
/// <exception cref="GraphicsContextMissingException">Generated when no GraphicsContext is current in the calling thread.</exception>
public static void Assert()
{
this.Destroy -= ContextDestroyed;
//available_contexts.Remove(((IGraphicsContextInternal)this).Context);
if (GraphicsContext.CurrentContext == null)
throw new GraphicsContextMissingException();
}
#endregion
#endregion
#region --- Public Members ---
#region public static IGraphicsContext CurrentContext
internal delegate ContextHandle GetCurrentContextDelegate();
internal static GetCurrentContextDelegate GetCurrentContext;
/// <summary>
/// Gets or sets the current GraphicsContext in the calling thread.
/// Gets the GraphicsContext that is current in the calling thread.
/// </summary>
public static GraphicsContext CurrentContext
{
@ -187,13 +182,6 @@ namespace OpenTK.Graphics
return null;
}
}
//set
//{
// if (value != null)
// value.MakeCurrent();
// else if (CurrentContext != null)
// CurrentContext.IsCurrent = false;
//}
}
#endregion
@ -231,20 +219,84 @@ namespace OpenTK.Graphics
#endregion
#region public static AvailableDisplayFormats
#endregion
#region --- Internal Members ---
bool inside_begin_region;
List<ErrorCode> error_list = new List<ErrorCode>();
// Indicates that we entered a GL.Begin() - GL.End() region.
[Conditional("DEBUG")]
internal void EnterBeginRegion()
{
inside_begin_region = true;
}
// Indicates that we left a GL.Begin() - GL.End() region.
[Conditional("DEBUG")]
internal void ExitBeginRegion()
{
inside_begin_region = false;
}
// Retrieve all OpenGL errors to clear the error list.
// See http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/geterror.html
[Conditional("DEBUG")]
internal void ResetErrors()
{
if (!inside_begin_region)
{
while (GL.GetError() != ErrorCode.NoError)
{ }
}
}
// Retrieve all OpenGL errors and throw an exception if anything other than NoError is returned.
[Conditional("DEBUG")]
internal void CheckErrors()
{
if (!inside_begin_region)
{
error_list.Clear();
ErrorCode error;
do
{
error = GL.GetError();
error_list.Add(error);
} while (error != ErrorCode.NoError);
if (error_list.Count != 1)
{
StringBuilder sb = new StringBuilder();
foreach (ErrorCode e in error_list)
{
sb.Append(e.ToString());
sb.Append(", ");
}
sb.Remove(sb.Length - 2, 2);
Debug.Assert(error_list.Count == 1, "OpenTK detected an OpenGL error.",
String.Format("The following errors where reported: \"{0}\"", sb.ToString()));
}
}
}
#endregion
#region public static void Assert()
#region --- Private Members ---
#region void ContextDestroyed(IGraphicsContext context, EventArgs e)
/// <summary>
/// Checks if a GraphicsContext exists in the calling thread and throws a GraphicsContextException if it doesn't.
/// Handles the Destroy event.
/// </summary>
public static void Assert()
/// <param name="context">The OpenTK.Platform.IGraphicsContext that was destroyed.</param>
/// <param name="e">Not used.</param>
void ContextDestroyed(IGraphicsContext context, EventArgs e)
{
if (GraphicsContext.CurrentContext == null)
throw new GraphicsContextMissingException();
this.Destroy -= ContextDestroyed;
//available_contexts.Remove(((IGraphicsContextInternal)this).Context);
}
#endregion
@ -344,60 +396,38 @@ namespace OpenTK.Graphics
#region --- IGraphicsContextInternal Members ---
#region Implementation
/// <summary>
/// Gets the platform-specific implementation of this IGraphicsContext.
/// </summary>
IGraphicsContext IGraphicsContextInternal.Implementation
{
get { return implementation; }
}
#endregion
#region void LoadAll()
/// <summary>
/// Loads all OpenGL extensions.
/// </summary>
void IGraphicsContextInternal.LoadAll()
{
(implementation as IGraphicsContextInternal).LoadAll();
}
#endregion
/// <internal />
/// <summary>Gets a handle to the OpenGL rendering context.</summary>
/// <summary>
/// Gets a handle to the OpenGL rendering context.
/// </summary>
ContextHandle IGraphicsContextInternal.Context
{
get { return ((IGraphicsContextInternal)implementation).Context; }
}
/*
/// <summary>
/// Gets the IWindowInfo describing the window associated with this context.
/// </summary>
IWindowInfo IGraphicsContextInternal.Info
{
get { return (implementation as IGraphicsContextInternal).Info; }
//internal set { (implementation as IGLContextInternal).Info = value; }
}
*/
/// <summary>
/// Gets the GraphicsMode of the context.
/// </summary>
public GraphicsMode GraphicsMode
{
get { return implementation.GraphicsMode; }
get { return (implementation as IGraphicsContextInternal).GraphicsMode; }
}
///// <summary>
///// Gets a System.IntPtr containing the handle to the OpenGL context which is current in the
///// calling thread, or IntPtr.Zero if no OpenGL context is current.
///// </summary>
///// <returns>A System.IntPtr that holds the handle to the current OpenGL context.</returns>
//ContextHandle IGLContextInternal.GetCurrentContext()
//{
// return (implementation as IGLContextInternal).GetCurrentContext();
//}
/// <summary>
/// Registers an OpenGL resource for disposal.
/// </summary>