Managed DirectX Tutorial 2 – Introduction to swap chains: Rendering to two panels at the same time

VIEWPORTS AND SWAP CHAINS

In this tutorial I’ll explain how you can use swap chains to create different views of the same scene. This tutorial should be fairly simple for you to understand and follow.

A swap chain is basically the process that DirectX uses when presenting a scene to the user. It draws the scene to an off-screen buffer (back buffer) and when it’s ready, it presents the image to the user swapping the back buffer (that contains the current frame) with the front buffer (that contains the last frame). Many swap chains can be created depending on the memory you have available. These are useful when you want to render a scene in more than one place. Think of an editor or a 3D program like 3D Studio Max, it has different views (using different cameras and projections) of the same scene. By default, DirectX creates one swap chain whenever you create the device.
The creation of a new swap chain is very easy. Let’s see what’s needed:

SwapChain sc = new SwapChain(device, presentParams);

All we need is the device a present parameters structure. So, if we only need these two things to create a new swap chain, how do we indicate to where we will render it? When creating a new device we indicate the handle to the control where we’re going to render our scene but in the case of swap chains we already have the device created, so, we use a field in the present parameters structure to indicate the handle:

presentParams.Window = panel.Handle;

4 WAY SPLIT VIEWPORTS

Now let’s draw something in 4 different viewports. I built a new control for this purpose, the 4 way splitter. To continue we need to take some special measures to assure that our viewports are rendered/updated correctly. What happens if we resize one or more viewports? we need to create new swap chains since viewport’s area has changed. I created a new control to help us on this task, the viewport control. This is a very simple control (for now, we might add some stuff to it later), it has two function callbacks: one for the render and one for the creation of the swap chain. This two callbacks are called whenever the control is painted or resized, respectively.

Viewport code

public delegate void RenderFuncDelegate(Viewport viewport);
private RenderFuncDelegate m_renderFunc;

public delegate void SwapChainFuncDelegate(Viewport viewport);
private SwapChainFuncDelegate m_swapChainFunc;

public RenderFuncDelegate RenderFunc
{
	[Browsable(false)]
	set { m_renderFunc = value; }
}

public SwapChainFuncDelegate SwapChainFunc
{
	[Browsable(false)]
	set { m_swapChainFunc = value; }
}

protected override void OnPaint(PaintEventArgs e)
{
	// render our scene
	if (m_renderFunc != null)
		m_renderFunc(this);
}

protected override void OnResize(EventArgs e)
{
	base.OnResize(e);

	// create new swap chain
	if (m_swapChainFunc != null)
		m_swapChainFunc(this);
}

Our main window is composed by a four way splitter with four viewports in each corner. We do some initializations with the device (see managed directx tutorial (part 1)) and create our swap chain and render functions so they can process requests for the viewports:

public void InitializeViewports()
{
  // save our viewports in an array
  m_viewports[0] = viewportTopLeft;
  m_viewports[1] = viewportTopRight;
  m_viewports[2] = viewportBottomLeft;
  m_viewports[3] = viewportBottomRight;

  // for each viewport register the delegate functions
  foreach(Viewport viewport in m_viewports)
  {
    viewport.SwapChainFunc = new WindowsControls.Viewport.SwapChainFuncDelegate(CreateSwapChain);
    viewport.RenderFunc = new WindowsControls.Viewport.RenderFuncDelegate(Render);
    CreateSwapChain(viewport);
  }
}

First we initialize an array with our viewports and for each viewport we associated the delegate functions that will handle the creation of the swap chain and render of the screen. Next our two delegate functions:

private void CreateSwapChain(Viewport viewport)
{
  // get the swap chain of the viewport
  SwapChain swapChain = ((SwapChain)viewport.Tag);

  // if we already have a swap chain created, get rid of it
  if(swapChain != null)
  {
    swapChain.Dispose();
  }

  PresentParameters presentParams = m_presentParams;
  presentParams.BackBufferWidth = viewport.Width;
  presentParams.BackBufferHeight = viewport.Height;

  // check if our buffer is valid
  if(presentParams.BackBufferWidth == 0 || presentParams.BackBufferHeight == 0)
  {
    return;
  }

  presentParams.DeviceWindowHandle = viewport.Handle;

  // save the swap chain in the viewport
  viewport.Tag = new SwapChain(m_device, m_presentParams);
}

private void Render(Viewport viewport)
{
  // get the swap chain of the viewport
  SwapChain swapChain = ((SwapChain)viewport.Tag);

  // safety check
  if (swapChain == null)
    return;

  // retrieve it's back buffer surface where we do the render
  Surface pBackBuffer = swapChain.GetBackBuffer(0);

  // set it as our current back buffer
  m_device.SetRenderTarget(0, pBackBuffer);

  // clear our back buffer
  m_device.Clear(ClearFlags.Target, Color.DarkSlateBlue, 1.0f, 0);

  // we don't need the surface anymore, get rid of it
  pBackBuffer.Dispose();

  // swap the screen buffer and back buffer to present our new data
  swapChain.Present();
}

And this is the end of another tutorial. I’ll add the C++/CLI code shortly (only C# for now), and other updates I might do to the code. Next time I’ll show you… well, I don’t know what I’ll do so stay tuned πŸ˜‰ Your feedback is appreciated, you can leave comments at the end of the page. See ya till next time! πŸ˜‰

Download Files:

C# version
You’re free to use this code as long as you don’t blame me for any changes/bugs that were introduced and don’t demand anything from me. Only download it if you accept these conditions.

References:

http://msdn.microsoft.com/directx/ – Microsoft DirectX Development Center
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_m/directx/directx9m.asp – DirectX 9.0 for Managed Code
http://forums.microsoft.com/ – MSDN Forums

Tagged , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *