Getting started with D3D in C#: InvalidCallException

Started by
2 comments, last by Wavarian 9 years, 9 months ago

Hey guys, figured I'd finally take a break from OpenGL to look at some Direct3D in C# and stumbled upon this tutorial:

http://msdn.microsoft.com/en-us/library/windows/desktop/bb153258%28v=vs.85%29.aspx

Works fine except for when you resize the window such that its client-height becomes 0; in which case the device suddenly becomes invalid and throws an InvalidCallException whenever you try to use it again.

This is the code I wrote while following the tutorial:


//
// D3DForm.cs
//



//
// Includes
//

using System.Drawing;
using System.Windows.Forms;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;



//
// D3DForm class definition
//

class D3DForm : Form
{
	//
	// Used to manage a D3D rendering device
	//

	private Device m_device = null;

	//=========================================================================
	//
	// DESCRIPTION
	//
	//		Constructor
	//
	// PARAMETERS
	//
	// RETURNS
	//
	//=========================================================================

	public D3DForm()
	{
		//
		// Initialize the form
		//

		this.ClientSize = new Size(640, 480);
	}

	//=========================================================================
	//
	// DESCRIPTION
	//
	//		Initializes the D3D rendering device
	//
	// PARAMETERS
	//
	// RETURNS
	//
	//		Returns true if successful
	//
	//=========================================================================

	public bool InitializeGraphics()
	{
		try
		{
			PresentParameters present_params = new PresentParameters();

			present_params.Windowed = true;
			present_params.SwapEffect = SwapEffect.Discard;

			m_device = new Device
			(
				0,
				DeviceType.Hardware,
				this,
				CreateFlags.SoftwareVertexProcessing,
				present_params
			);
		}
		catch(DirectXException)
		{
			return false;
		}

		return true;
	}

	//=========================================================================
	//
	// DESCRIPTION
	//
	//		Renders the scene
	//
	// PARAMETERS
	//
	// RETURNS
	//
	//=========================================================================

	public void Render()
	{
		if(m_device != null)
		{
			m_device.Clear(ClearFlags.Target, Color.Blue, 1.0f, 0); // InvalidCallException thrown
			m_device.BeginScene();

			m_device.EndScene();
			m_device.Present();
		}
	}

	//=========================================================================
	//
	// DESCRIPTION
	//
	//		Application entry point
	//
	// PARAMETERS
	//
	// RETURNS
	//
	//=========================================================================

	private static void Main()
	{
		using(D3DForm form = new D3DForm())
		{
			if(form.InitializeGraphics())
			{
				form.Show();

				//
				// Application loop
				//

				while(form.Created)
				{
					form.Render();

					Application.DoEvents();
				}
			}
		}
	}
}

How do I repair the device once this happens? How do I prevent it from becoming invalid - do I have to prevent the window's client-size from becoming zero?

Thanks!

Advertisement

I'm guessing that I'll need to reset the device whenever rendering fails like so:


//
// D3DForm.cs
//



//
// Includes
//

using System.Drawing;
using System.Windows.Forms;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;



//
// D3DForm class definition
//

class D3DForm : Form
{
	//
	// Used to manage a D3D rendering device
	//

	private Device m_device = null;

	//=========================================================================
	//
	// DESCRIPTION
	//
	//		Constructor
	//
	// PARAMETERS
	//
	// RETURNS
	//
	//=========================================================================

	public D3DForm()
	{
		//
		// Initialize the form
		//

		this.ClientSize = new Size(640, 480);
	}

	//=========================================================================
	//
	// DESCRIPTION
	//
	//		Initializes the D3D rendering device
	//
	// PARAMETERS
	//
	// RETURNS
	//
	//		Returns true if successful
	//
	//=========================================================================

	public bool InitializeGraphics()
	{
		try
		{
			PresentParameters present_params = new PresentParameters();

			present_params.Windowed = true;
			present_params.SwapEffect = SwapEffect.Discard;

			if(m_device == null)
			{
				m_device = new Device
				(
					0,
					DeviceType.Hardware,
					this,
					CreateFlags.SoftwareVertexProcessing,
					present_params
				);
			}
			else
			{
				m_device.Reset(present_params);
			}
		}
		catch(DirectXException)
		{
			return false;
		}

		return true;
	}

	//=========================================================================
	//
	// DESCRIPTION
	//
	//		Renders the scene
	//
	// PARAMETERS
	//
	// RETURNS
	//
	//=========================================================================

	public void Render()
	{
		if(m_device != null)
		{
			try
			{
				m_device.Clear(ClearFlags.Target, Color.Blue, 1.0f, 0);
				m_device.BeginScene();

				m_device.EndScene();
				m_device.Present();
			}
			catch(DirectXException)
			{
				InitializeGraphics();
			}
		}
	}

	//=========================================================================
	//
	// DESCRIPTION
	//
	//		Application entry point
	//
	// PARAMETERS
	//
	// RETURNS
	//
	//=========================================================================

	private static void Main()
	{
		using(D3DForm form = new D3DForm())
		{
			if(form.InitializeGraphics())
			{
				form.Show();

				//
				// Application loop
				//

				while(form.Created)
				{
					form.Render();

					Application.DoEvents();
				}
			}
		}
	}
}

No idea if this is the proper solution though.

In D3D9 you can have a "Lost Device" scenario, and you have to recover from it by calling Reset on your device. It's a real pain to deal with in a robust way, and is the source of a lot of errors. Fortunately they fixed it for D3D10/D3D11.

I should definitely warn you that the "Managed DirectX" library you're using is very old, and hasn't been updated in many years. Microsoft essentially abandoned it, and left the task of a managed DirectX wrapper up to the community. Earlier on SlimDX was the most popular Managed DX wrapper, but these days SharpDX is much more active and up-to-date with the latest DirectX versions. I would recommend using SharpDX instead if you're looking to actually do any DX app development, and I would also recommend using D3D11 unless you really need to target Windows XP.

Many thanks - I'll check out SharpDX

This topic is closed to new replies.

Advertisement