2

Drawing a DIB Section in WPF

One of the most exciting new features in the forthcoming SharpGL 2.0 (which was actually planned for 2.1 but has been moved to 2.0) is the facility to do OpenGL drawing in a WPF control. This isn’t done via a WinFormsHost (which has unpleasant side-effects due to Airspace, see http://msdn.microsoft.com/en-us/library/aa970688(v=VS.100).aspx) but actually via an Image in a WPF UserControl.

What does this mean? Well it means that when you use the SharpGL.WPF libraries OpenGLControl you get what is essentially a genuine WPF control – you can overlay other controls on top of it, with transparency and bitmap effects and do everything you’d normally be able to do with a WPF control.

How this works is an interesting bit of code so here are the details.

When using a WPF OpenGL control we render either using a DIBSectionRenderContextProvider, or a FBORenderContextProvider. Here’s the difference:

DIBSectionRenderContextProvider - Renders directly to a DIB Section. Supported with any version of OpenGL but never hardware accelerated.

FBORenderContextProvider - Renders to a Framebuffer object, via the GL_EXT_framebuffer_object extension. This is fully hardware accelerated but only supported in OpenGL 1.3 and upwards. The resultant framebuffer is copied into a DIB section also.

With either render context provider we end up with a DIB section that contains the frame – here’s how we can render it:

/// <summary>
/// Converts a <see cref="System.Drawing.Bitmap"/> into a WPF <see cref="BitmapSource"/>.
/// </summary>
/// <remarks>Uses GDI to do the conversion. Hence the call to the marshalled DeleteObject.
/// </remarks>
/// <param name="source">The source bitmap.</param>
/// <returns>A BitmapSource</returns>
public static BitmapSource HBitmapToBitmapSource(IntPtr hBitmap)
{
    BitmapSource bitSrc = null;
    
    try
    {
        bitSrc = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
            hBitmap,
            IntPtr.Zero,
            Int32Rect.Empty,
            BitmapSizeOptions.FromEmptyOptions());
    }
    catch (Win32Exception)
    {
        bitSrc = null;
    }
    finally
    {
        Win32.DeleteObject(hBitmap);
    }

    return bitSrc;
}

This function allows us to turn a handle to a DIB section into a BitmapSource. The OpenGLControl is essentially just an image, and with each frame we simply set the BitmapSource to the newly rendered DIBSection.

The version of the code this post relates to is: http://sharpgl.codeplex.com/SourceControl/changeset/view/4805

The WPF example renders the Utah Teapot (http://en.wikipedia.org/wiki/Utah_teapot) directly in a WPF application. We’re still pre-beta but grab the code if you want to try OpenGL in WPF.

2

Importing OpenGL Extensions Functions with wglGetProcAddress

There are only a small set of the core OpenGL functions that can be imported via p/invoke – the majority of OpenGL functions are actually extension functions which are supported only on specific video cards. OpenGL offers a function called wglGetProcAddress which can return the address of a named function – but how do we deal with this in the managed world?

Here’s a brief description of how it’s handled in SharpGL. As of this morning, SharpGL’s latest version contains all core functions up to OpenGL 4.2 and all standard extensions up to OpenGL 4.2. This takes the support for OpenGL to the latest version – August 2011.

First we must import the wglGetProcAddress function:

[DllImport("opengl32.dll")]
public static extern IntPtr wglGetProcAddress(string name);

This is the correect p/invoke method of importing this function, however it returns an IntPtr, which we cannot call as a function. We could change the return type to a delegate but this function can return essentially any type of delegate – so where do we go from here?

Well the next step is to define the delegates we want to use – they must have exactly the same name as the OpenGL functions and use the correct parameters for marshalling. Here are a couple of delegates for OpenGL 1.4:

private delegate void glBlendFuncSeparate (uint sfactorRGB, uint dfactorRGB, uint sfactorAlpha, uint dfactorAlpha);

private delegate void glMultiDrawArrays (uint mode, int[] first, int[] count, int primcount);

Now we must create a function which will turn an IntPtr into a delegate and invoke it:

/// <summary>
/// The set of extension functions.
/// </summary>
private Dictionary<string, Delegate> extensionFunctions = new Dictionary<string, Delegate>();

/// <summary>
/// Invokes an extension function.
/// </summary>
/// <typeparam name="T">The extension delegate type.</typeparam>
/// <param name="args">The arguments to the pass to the function.</param>
/// <returns>The return value of the extension function.</returns>
private object InvokeExtensionFunction<T>(params object[] args)
{
    //  Get the type of the extension function.
    Type delegateType = typeof(T);

    //  Get the name of the extension function.
    string name = delegateType.Name;

    //  Does the dictionary contain our extension function?
    Delegate del = null;
    if (extensionFunctions.ContainsKey(name) == false)
    {
        //  We haven't loaded it yet. Load it now.
        IntPtr proc = Win32.wglGetProcAddress(name);
        if (proc == IntPtr.Zero)
            throw new Exception("Extension function " + name + " not supported");

        //  Get the delegate for the function pointer.
        del = Marshal.GetDelegateForFunctionPointer(proc, delegateType);
        if (del == null)
            throw new Exception("Extension function " + name + " not supported");

        //  Add to the dictionary.
        extensionFunctions.Add(name, del);
    }

    //  Get the delegate.
    del = extensionFunctions[name];

    //  Try and invoke it.
    object result = null;
    try
    {
        result = del.DynamicInvoke(args);
    }
    catch
    {
        throw new Exception("Cannot invoke extension function " + name);
    }

    return result;
}

We now have a generalised way to invoke an extension function. The loaded functions are stored in a dictionary keyed by name so that the heavy lifting is only done the first time we try to invoke the function.  We can finally add the functions to the class as below:

public void BlendFuncSeparate(uint sfactorRGB, uint dfactorRGB, uint sfactorAlpha, uint dfactorAlpha)
{
    InvokeExtensionFunction<glBlendFuncSeparate>(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
}

public void MultiDrawArrays(uint mode, int[] first, int[] count, int primcount)
{
    InvokeExtensionFunction<glMultiDrawArrays>(mode, first, count, primcount);
}

This is pretty cool – we can invoke any extension function as long as we have defined a delegate for it. What’s more, by making the InvokeExtensionFunction function public we can allow other developers to provide their own delegates and invoke other extension functions.

This is the technique used in SharpGL 2.0 to import extension functions – the Core/OpenGLExtensions.cs file contains thousands of lines of functions defined like this, however knowing how to invoke any kind of delegate is a useful skill in the managed world, so this trick could be used in other places.

The version of SharpGL this post relates to is at:

http://sharpgl.codeplex.com/SourceControl/changeset/view/4474

3

Visual Studio Code Analysis – Buffer Overruns

Today I was looking through some fairly old source code in a large solution, large in this case is ~300 projects and about 1 million lines of code. Parts of the code base are very old – at some stage a decision was made to disable warning C4996. The problem I came across is reduced to its most simple form below:

// AnalysisExample.cpp : An example of how static analysis can help.
//

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
	//	Create two buffers, one small, one large.
	TCHAR storageSmall[13];
	TCHAR storageLarge[128];

	//	Get a pointer to a string literal.
	TCHAR* str = _T("Here is a string that is too long.");
	
	//	Now do something very dangerous.
	::_tcscpy(storageLarge, str);
	::_tcscpy(storageSmall, storageLarge);

	return 0;
}

Now in a sensible world with this warning enabled, we would get the following when compiling:

analysisexample.cpp(14): warning C4996: 'wcscpy': 
This function or variable may be unsafe. Consider using 
wcscpy_s instead. To disable deprecation, use 
_CRT_SECURE_NO_WARNINGS. See online help for details.
analysisexample.cpp(15): warning C4996: 'wcscpy': 
This function or variable may be unsafe. Consider using 
wcscpy_s instead. To disable deprecation, use 
_CRT_SECURE_NO_WARNINGS. See online help for details.

The warning is telling us that wcscpy (which is what _tcscpy translates to in a Unicode build) is unsafe, which indeed it is as it does no buffer checking. However, when you migrate a Visual Studio 2005 solution to 2008 or straight to 2010 then suddenly you’ll get lots of warnings like this. If there are thousands of warnings and they’re masking other more important ones then you can see why maybe you’d consider disabling them.

Why is this a bug?

In case you didn’t see it, a string literal that is 34 characters long (68 bytes) is copied to a buffer 128 characters long. OK so far. Then we copy the 34 characters into a smaller 13 character buffer – this causes a buffer overrun on the stack. In reality what happens is variables used subsequently in the function get overwritten unexpectedly. Or don’t. Generally the worst case is that nothing odd happens during testing, but then the code blows up on-site with the customer, typically on something business critical like a database server – something it’s hard to debug on.

Visual Studio’s Code Analysis tool is a life-saver. If you haven’t used it before, get used to running it on all of your projects. Here’s what happens when we run it (Analyze > Run Code Analysis On Solution):

1>analysisexample.cpp(18): warning C6202: 
Buffer overrun for 'storageSmall', which is possibly 
stack allocated, in call to 'wcscpy': length '256' 
exceeds buffer size '26'

Code analysis has shown us exactly the problem, even with the warning disabled.

So why is this important? Imagine we have the following four lines spread across four files:

//	Defined in Header1.h
static const int LENGTH1 = 13;

//	Defined in Header2.h
static const int LENGTH2 = 128;

//	Defined in Header3.h
typedef TCHAR LineOne[LENGTH1];

//	Defined in Header4.h
typedef TCHAR LineTwo[LENGTH2];

Our code could now look like this:

//	Create two buffers, one small, one large.
LineOne storageSmall;
LineTwo storageLarge;

//	Get a pointer to a string literal.
TCHAR* str = _T("Here is a string that is too long.");
	
//	Now do something very dangerous.
::_tcscpy(storageLarge, str);
::_tcscpy(storageSmall, storageLarge);

Suddenly things aren’t looking quite so obviously wrong – now imagine the different lines that make up this bug are spread across more files – or even more projects. Static analysis takes only a few seconds to run, unfortunately it’s only available in the more expensive versions of visual studio.

An even better solution – don’t run the risk, use _tcscpy_s rather than _tcscpy - it checks the buffer length without even requiring a single extra parameter in the example above.

1

How ISupportInitialize Can Help

I have recently come to discover the ISupportInitialize interface and found that it is extremely useful when developing more complicated WinForms controls.

Here’s the link to the ISupportInitialize interface on MSDN: http://msdn.microsoft.com/en-us/library/system.componentmodel.isupportinitialize.aspx but here I’ll describe how it can be useful.

The Problem

I have a fairly complicated WinForms usercontrol called ‘OpenGLControl’, which allows OpenGL commands to be used to render 3D scenes in a C# WinForms application. The control has properties which are interdependent to each other. If these properties are set in the designer, code like this is generated:

// 
// openGLControl1
// 
this.openGLControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                | System.Windows.Forms.AnchorStyles.Left)
                | System.Windows.Forms.AnchorStyles.Right)));
this.openGLControl1.BitDepth = 32;
this.openGLControl1.DrawRenderTime = true;
this.openGLControl1.FrameRate = 29.41176F;
this.openGLControl1.Location = new System.Drawing.Point(12, 12);
this.openGLControl1.Name = "openGLControl1";
this.openGLControl1.RenderContextType = SharpGL.RenderContextType.NativeWindow;
this.openGLControl1.Size = new System.Drawing.Size(768, 379);
this.openGLControl1.TabIndex = 0;
this.openGLControl1.OpenGLDraw += new System.Windows.Forms.PaintEventHandler(this.openGLControl1_OpenGLDraw);

Now this leads to a problem – BitDepth, OpenGLDraw, FrameRate etc must all be declared BEFORE the Size property is set – but how can we control this? Or how can we deal with this situation in general?

This is where the ISupportInitialize interface comes in. If a control is added to the design surface with this interface, we’ll get the following code wrapped around the designer code:

private void InitializeComponent()
{
    System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormExample1));
    this.label1 = new System.Windows.Forms.Label();
    this.linkLabel1 = new System.Windows.Forms.LinkLabel();
    this.openGLControl1 = new SharpGL.OpenGLControl();
    ((System.ComponentModel.ISupportInitialize)(this.openGLControl1)).BeginInit();
    this.SuspendLayout();
    //
    //  ...ordianry designer code...
    //
    ((System.ComponentModel.ISupportInitialize)(this.openGLControl1)).EndInit();
    this.ResumeLayout(false);
    this.PerformLayout();
}

Now just implement the ISupportInitialize interface in your control – in the ‘EndInit’ function do any processing that depends on the interdependent properties. This is the earliest point that we can do processing like this. In certain circumstances, knowing about this interface can save you a lot of trouble.

0

SharpGL 2.0: Hardware Acceleration

It took a bit of working out, but finally SharpGL can support hardware acceleration. Previously, all rendering in SharpGL was done to a DIB Section, the result of this would be blitted to the screen. Much playing around has shown that in fact this is problematic – rendering to DIB sections can never be hardware accelerated.

To hardware accelerate rendering, the rendering must be to a window or a pixel buffer. This has introduced an architectural change to SharpGL – the handling of a render context and any supporting objects (DIB sections, windows etc) is handled by a class that implements the IRenderContextProvider interface. This interface specifies that render context providers must be able to Create, Destroy, Resize and Blit.

SharpGL 2.0 now has two render context providers, DIBSectionRenderContext provider which uses a DIB Section as previously and HiddenWindowRenderContextProvider which renders to a hidden window. The hidden window render context provider allows full hardware acceleration.

I will be adding a new example application to the solution which shows rendering with the two providers side by side.

So don’t forget: DIB Sections can’t be accelerated.

0

P/Invoke Performance

SharpGL 2.0 has no P/Invoke – all native functions are called by a C++/CLI class library (OpenGLWrapper if you’re getting the code from CodePlex) which calls functions directly. This means there’s no more importing of PIXELFORMAT structures and so on.

The thinking behind this was that a C++/CLI wrapper is faster than P/Invoke for a talkative API like OpenGL – but is this actually the case? In my new article on the CodeProject I investigate the performance differences between these two methods.

http://www.codeproject.com/KB/dotnet/pinvokeperformance.aspx

0

Trials and Tribulations with SharpGL 2.0

SharpGL has not been updated for a while, the original CoreProject article is at: http://www.codeproject.com/KB/openGL/sharpgl.aspx

Recently I have begun work on SharpGL 2.0, with plans to address some of the issues people have had with SharpGL 1.83. In preparation there is a public accessible repository on CodePlex: http://sharpgl.codeplex.com/ check it soon, it will shortly be online.

Trying to squeeze acceptible performance from SharpGL has so far been an interesting task, I have found out many interesting things on the way, I’ll be posting small snippets as I work on SharpGL 2.0 describing how I’m improving the performance and structure of the library.